反射让你在运行时动态获取类的信息(字段、方法、构造方法),并调用它们。框架(如 Spring)大量使用反射。

1. 获取 Class 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Person {
private String name;
public int age;

public Person() {}

public Person(String name, int age) {
this.name = name;
this.age = age;
}

public void sayHello() {
System.out.println("你好,我是" + name);
}

private void secret() {
System.out.println("这是私有方法");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class GetClassDemo {
public static void main(String[] args) throws Exception {
// 方式一:类名.class
Class<?> cls1 = Person.class;

// 方式二:对象.getClass()
Person p = new Person();
Class<?> cls2 = p.getClass();

// 方式三:Class.forName(全限定类名)
Class<?> cls3 = Class.forName("Person");

System.out.println(cls1 == cls2); // true
System.out.println(cls1 == cls3); // true(同一个类的 Class 对象唯一)
}
}

2. 获取类的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ClassInfoDemo {
public static void main(String[] args) {
Class<?> cls = Person.class;

// 类名
System.out.println(cls.getName()); // Person
System.out.println(cls.getSimpleName()); // Person

// 所有字段
System.out.println("--- 字段 ---");
for (Field f : cls.getDeclaredFields()) {
System.out.println(f.getName() + " : " + f.getType().getSimpleName());
}

// 所有方法
System.out.println("--- 方法 ---");
for (Method m : cls.getDeclaredMethods()) {
System.out.println(m.getName());
}
}
}

3. 动态创建对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.lang.reflect.Constructor;

public class CreateObjectDemo {
public static void main(String[] args) throws Exception {
Class<?> cls = Person.class;

// 无参构造
Constructor<?> ctor1 = cls.getConstructor();
Object obj1 = ctor1.newInstance();

// 有参构造
Constructor<?> ctor2 = cls.getConstructor(String.class, int.class);
Object obj2 = ctor2.newInstance("小明", 18);

Person p = (Person) obj2;
p.sayHello(); // 你好,我是小明
}
}

4. 调用方法

1
2
3
4
5
6
7
8
9
10
11
12
import java.lang.reflect.Method;

public class InvokeDemo {
public static void main(String[] args) throws Exception {
Person p = new Person("小红", 20);
Class<?> cls = p.getClass();

// 获取 sayHello 方法并调用
Method method = cls.getMethod("sayHello");
method.invoke(p); // 你好,我是小红
}
}

5. 访问私有字段和方法

用 setAccessible(true) 可以绕过 private 限制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class PrivateAccessDemo {
public static void main(String[] args) throws Exception {
Person p = new Person("小明", 18);
Class<?> cls = p.getClass();

// 访问私有字段 name
Field nameField = cls.getDeclaredField("name");
nameField.setAccessible(true); // 关键:绕过 private
System.out.println(nameField.get(p)); // 小明

// 修改私有字段
nameField.set(p, "改名了");
System.out.println(nameField.get(p)); // 改名了

// 调用私有方法 secret
Method secretMethod = cls.getDeclaredMethod("secret");
secretMethod.setAccessible(true);
secretMethod.invoke(p); // 这是私有方法
}
}

6. 反射的应用场景

  • 框架:Spring、MyBatis 等框架靠反射自动创建对象、注入依赖
  • 注解处理:运行时读取注解信息
  • 动态代理:生成代理类
  • 序列化:自动读写对象的字段

小结

  • Class 对象三种获取方式:.class、.getClass()、Class.forName
  • getDeclaredFields() / getDeclaredMethods() 获取成员
  • newInstance() 创建对象,invoke() 调用方法
  • setAccessible(true) 可访问私有成员