什么是反射
Class 是「类的说明书」,反射就是拿着这本说明书,在程序运行时查看这个类、创建它、找它的方法和属性,然后动态操作它。
一、先看不用反射的情况
public class Person {
private String name = "张三";
public void sayHello() {
System.out.println("你好,我是" + name);
}
public void eat(String food) {
System.out.println("我正在吃" + food);
}
}平时就这么用:
Person person = new Person();
person.sayHello();// 你好,我是张三
person.eat("苹果");关键特点:写代码的时候我就已经知道这个类叫 Person,也知道它有 sayHello()。
二、如果事先不知道这个类呢
比如需求是:用户输入一个类名,程序自动创建这个类的对象。
请输入类名:
Person问题在于,编译的时候我不知道用户以后会输入什么,可能是 Student、Dog、Cat、Order、User……总不能写一长串判断:
if (name.equals("Person")) {
Person p = new Person();
} else if (name.equals("Student")) {
Student s = new Student();
} else if (...) {
// 没完没了
}于是反射登场。
三、反射的核心:Class
Java 提供了 Class 类,可以把它理解成某一个 Java 类的说明书 / 身份证。
Class<Person> clazz = Person.class;
System.out.println(clazz.getName());// Person一本说明书里能翻到这些内容:
- 类名、父类、实现的接口
- 构造方法
- 普通方法
- 成员变量

拿到 Class 对象有三种方式:
| 写法 | 适用场景 |
|---|---|
Person.class | 编译期就知道类名 |
person.getClass() | 手里已经有这个类的对象 |
Class.forName("com.demo.Person") | 只有一个字符串,反射的关键入口 |
Class.forName()里要写全限定类名(包名 + 类名)。如果类是写在默认包里的,写"Person"也能跑,但实际项目里类都在包里,所以下面统一用com.demo.Person。
四、只用字符串也能拿到类的信息
这才是反射真正有意思的地方。我现在手里只有一个字符串:
String className = "com.demo.Person";
Class<?> clazz = Class.forName(className);
System.out.println(clazz.getName());"com.demo.Person"
↓ Class.forName()
Class 对象
↓
我开始知道这个类的信息这就是运行时获取类的信息。
五、Class 对象上能问什么
Class<?> clazz = Class.forName("com.demo.Person");
for (Method method : clazz.getDeclaredMethods()) {
System.out.println(method.getName());
}
// sayHello
// eat注意,这里没有创建 Person 对象,也没有写过 new Person()。我只是拿着 Class 问了一句:Person,你有哪些方法?
六、创建对象并调用方法
Class<?> clazz = Class.forName("com.demo.Person");
Object person = clazz.getDeclaredConstructor().newInstance();
Method method = clazz.getDeclaredMethod("sayHello");
method.invoke(person); // 你好,我是张三这四行就是很典型的反射。
person 的类型是 Object,因为写代码的时候根本不知道它到底是什么类。
两个要强调的点:
newInstance()要求这个类有无参构造。只有带参构造时,要写成clazz.getDeclaredConstructor(String.class).newInstance("张三")。getDeclaredMethod("sayHello")取的是无参方法。调带参方法要补上参数类型,比如getDeclaredMethod("eat", String.class)。
七、正常调用和反射调用的区别

| 正常调用 | 反射调用 | |
|---|---|---|
| 类名和方法名 | 写死在代码里 | 存成字符串,可以来自配置文件、数据库、用户输入、注解 |
| 拿到对象 | new Person() | Class.forName(...) → newInstance() |
| 调用方法 | person.sayHello() | getDeclaredMethod("sayHello") → invoke(person) |
| 什么时候确定 | 编译期 | 运行期 |
两者用一句话对比:
- 正常调用:我提前知道你叫 Person,也知道你有
sayHello方法 - 反射调用:我现在才知道你是谁,然后自己去你的说明书里找
sayHello,再调用它
八、反射能碰到 private
平时直接访问私有字段会编译报错:
Person person = new Person();
System.out.println(person.name); // ❌ name 是 private反射可以:
Object person = clazz.getDeclaredConstructor().newInstance();
Field field = clazz.getDeclaredField("name");
field.setAccessible(true); // 关掉访问检查
System.out.println(field.get(person)); // 张三
field.set(person, "李四");
System.out.println(field.get(person)); // 李四私有方法也一样:
Method method = clazz.getDeclaredMethod("secret");
method.setAccessible(true);
method.invoke(person); // 这是我的秘密
setAccessible(true)只是跳过了访问检查,字段本身并没有被改成 public。
所以反射一共能做六件事:
反射
│
├── 看类的信息
├── 创建对象
├── 找方法
├── 调用方法
├── 找字段
└── 修改字段九、「动态」到底指什么
这是反射里最容易让初学者懵的词。
普通代码:
Person p = new Person();
p.sayHello();编译之前类名和方法名就全部写死了。
反射:
String className = "com.demo.Person";
Class<?> clazz = Class.forName(className);
Object obj = clazz.getDeclaredConstructor().newInstance();
Method method = clazz.getDeclaredMethod("sayHello");
method.invoke(obj);这里的 className 可以来自:
配置文件
数据库
用户输入
框架配置
注解程序运行起来以后才决定「我要操作哪个类」。这就是动态。
十、回头看那句话
反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法。
翻译成人话就是:
clazz.getDeclaredFields()→ 「Person,你有哪些属性?」clazz.getDeclaredMethods()→ 「Person,你有哪些方法?」clazz.getDeclaredConstructors()→ 「Person,你有哪些构造方法?」
补充一个容易混的细节:
getDeclaredXxx()拿的是本类声明的全部成员,包括 private;而getXxx()只拿 public 的,但包含从父类继承来的。
十一、框架为什么离不开反射

Spring
我明明没写 new UserService(),Spring 怎么知道要创建 UserService?
Spring 启动
↓
扫描项目中的类
↓
发现 @Service
↓
获取这个类的信息
↓
创建 UserService 对象
↓
放进 Spring 容器这里大量用到反射 + 注解。
MyBatis
@Mapper
public interface UserMapper {
User findById(Long id);
}UserMapper 明明只是个接口,连实现类都没写,为什么 @Autowired 之后就能直接调?背后是动态代理 + 反射,MyBatis 帮你生成了代理对象。
Spring MVC
浏览器访问 GET /user,Spring 怎么知道它对应 getUser()?
扫描类
↓
找到 @GetMapping
↓
读取 "/user"
↓
记录 "/user" → getUser()
↓
请求来了
↓
找到对应方法
↓
反射调用十二、面试怎么答
理解之后,答案可以压缩成三句:
Java 反射是指程序在运行时动态获取类的信息,并对类或对象进行操作的机制。
可以通过 Class 对象获取类的名称、字段、方法、构造器等信息,也可以动态创建对象、调用方法、访问字段。例如用 Class.forName() 根据类名拿到 Class 对象,再用 getDeclaredConstructor().newInstance() 创建对象,用 getDeclaredMethod() 拿到方法,最后用 invoke() 调用。
Spring、MyBatis 等框架大量使用了反射,它让框架能够在运行时根据配置、注解等信息动态创建对象和调用方法。