一、反射概述
1.1 什么是反射
反射(Reflection) 是 Java 在运行时动态获取和操作类结构的技术。它允许程序在运行状态中:
- 获知任意对象所属的类
- 构造任意一个类的对象
- 获知任意一个类的成员变量、方法、构造器等信息
- 调用任意一个对象的方法、访问与修改其属性,即使这些成员是
private的
1.2 反射的核心原理:Class 对象
- 每个
.class字节码被类加载器加载后,JVM 会为之生成唯一的java.lang.Class对象 - 该类的所有实例共享同一个 Class 对象
- Class 对象是反射的入口,包含类名、包名、接口、方法、字段、注解等完整结构信息
二、获取 Class 对象的四种方式
| 方式 | 代码示例 | 适用场景 |
|---|---|---|
| 对象实例 | obj.getClass() | 已有实例时 |
| 类字面量 | User.class | 编译期已知类名 |
| 全限定名 | Class.forName("com.example.User") | 配置驱动、插件等 |
| 类加载器 | ClassLoader.loadClass("com.example.User") | 自定义加载逻辑 |
// 示例:四种获取 Class 的方式
String str = "hello";
// 1. 通过对象实例
Class<?> c1 = str.getClass();
// 2. 通过类字面量
Class<?> c2 = String.class;
// 3. 通过全限定名(会执行静态块)
Class<?> c3 = Class.forName("java.lang.String");
// 4. 通过类加载器(不执行静态块)
Class<?> c4 = ClassLoader.getSystemClassLoader().loadClass("java.lang.String");
System.out.println(c1 == c2 && c2 == c3 && c3 == c4); // true,同一 Class 对象
Class.forName() 与 ClassLoader.loadClass() 区别:
Class.forName():默认执行类的静态初始化块(如 JDBC 驱动注册)ClassLoader.loadClass():仅加载,不执行静态初始化,常用于热加载、插件化
// 示例:forName 会执行静态块,loadClass 不会
class Driver {
static { System.out.println("Driver 静态块执行"); }
}
Class.forName("Driver"); // 输出:Driver 静态块执行
// loadClass 则不会输出
三、反射 API 详解
3.1 反射相关包与类层次
java.lang.reflect
├── AccessibleObject ← Field、Method、Constructor 的基类
│ ├── Field 成员变量
│ ├── Method 成员方法
│ └── Constructor 构造方法
├── Modifier 修饰符解析
├── Parameter 参数元信息(Java 8+)
├── Array 动态数组操作
├── Type(及其实现) 泛型类型表示
│ ├── ParameterizedType 如 List<String>
│ ├── TypeVariable 如 T、E
│ ├── WildcardType 如 ? extends Number
│ └── GenericArrayType 如 T[]
└── Proxy 动态代理
3.2 Class 类常用方法
| 方法 | 说明 |
|---|---|
getName() | 全限定类名 |
getSimpleName() | 短类名 |
getPackage() | 包信息 |
getSuperclass() | 父类 Class |
getInterfaces() | 实现接口数组 |
getModifiers() | 修饰符整型,配合 Modifier 解析 |
newInstance() | 无参构造创建实例(已废弃,推荐 Constructor.newInstance()) |
// Class 常用方法示例
Class<?> clazz = String.class;
System.out.println(clazz.getName()); // java.lang.String
System.out.println(clazz.getSimpleName()); // String
System.out.println(clazz.getPackage()); // package java.lang
System.out.println(clazz.getSuperclass()); // class java.lang.Object
3.3 构造方法(Constructor)
| 方法 | 说明 |
|---|---|
getConstructors() | 所有 public 构造方法 |
getDeclaredConstructors() | 所有声明构造(含 private) |
getConstructor(Class<?>...) | 指定参数类型的 public 构造 |
getDeclaredConstructor(Class<?>...) | 指定参数类型的声明构造 |
Constructor.newInstance(Object...) | 使用该构造创建实例 |
// Constructor 示例:通过反射创建对象
// import java.lang.reflect.Constructor;
// 假设有类:class User { public User(){} public User(String n, int a){} private User(String s){} }
Class<?> clazz = User.class;
// 无参构造
Constructor<?> noArg = clazz.getDeclaredConstructor();
User user1 = (User) noArg.newInstance();
// 有参构造
Constructor<?> withArgs = clazz.getDeclaredConstructor(String.class, int.class);
User user2 = (User) withArgs.newInstance("张三", 25);
// 私有构造(需 setAccessible)
Constructor<?> priv = clazz.getDeclaredConstructor(String.class);
priv.setAccessible(true);
User user3 = (User) priv.newInstance("私有构造");
// 标准库示例:ArrayList 无参构造
Constructor<?> c = ArrayList.class.getDeclaredConstructor();
ArrayList<?> list = (ArrayList<?>) c.newInstance();
3.4 成员变量(Field)
| 方法 | 说明 |
|---|---|
getFields() | 所有 public 字段(含继承) |
getDeclaredFields() | 所有声明字段(含 private) |
getField(String) | 指定名称的 public 字段 |
getDeclaredField(String) | 指定名称的声明字段 |
Field.get(Object) | 读取实例字段值 |
Field.set(Object, Object) | 设置实例字段值 |
Field.getGenericType() | 泛型类型(含 ParameterizedType 等) |
// Field 示例:读写字段(含私有)
class Person {
public String name;
private int age;
}
Person p = new Person();
Class<?> clazz = Person.class;
// 读写 public 字段
Field nameField = clazz.getField("name");
nameField.set(p, "李四");
System.out.println(nameField.get(p)); // 李四
// 读写 private 字段
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(p, 30);
System.out.println(ageField.get(p)); // 30
3.5 成员方法(Method)
| 方法 | 说明 |
|---|---|
getMethods() | 所有 public 方法(含继承) |
getDeclaredMethods() | 所有声明方法(含 private) |
getMethod(String, Class<?>...) | 指定名称和参数类型的 public 方法 |
getDeclaredMethod(String, Class<?>...) | 指定名称和参数类型的声明方法 |
Method.invoke(Object, Object...) | 调用方法,第一个参数为实例(静态方法传 null) |
getParameterTypes() | 参数类型数组 |
getReturnType() | 返回类型 |
getGenericReturnType() | 泛型返回类型 |
// Method 示例:反射调用方法
class Calculator {
public int add(int a, int b) { return a + b; }
private int multiply(int a, int b) { return a * b; }
}
Calculator calc = new Calculator();
Class<?> clazz = Calculator.class;
// 调用 public 方法
Method addMethod = clazz.getMethod("add", int.class, int.class);
Object result = addMethod.invoke(calc, 3, 5);
System.out.println(result); // 8
// 调用 private 方法
Method mulMethod = clazz.getDeclaredMethod("multiply", int.class, int.class);
mulMethod.setAccessible(true);
Object mulResult = mulMethod.invoke(calc, 4, 5);
System.out.println(mulResult); // 20
// 静态方法:第一个参数传 null
Method parseInt = Integer.class.getMethod("parseInt", String.class);
Object num = parseInt.invoke(null, "42"); // 42
3.6 访问控制:AccessibleObject 与 setAccessible
Field、Method、Constructor 均继承自 AccessibleObject,提供:
setAccessible(boolean flag):关闭 Java 语言访问检查,可访问 private、protected 等- 注意:并非改变成员本身的访问权限,而是屏蔽运行时的权限校验
- 即使对 public 成员调用
setAccessible(true),也能降低反射权限检查带来的开销,显著提升性能(约 20 倍)
3.7 修饰符:Modifier
int getModifiers():返回修饰符的位编码Modifier.isPublic(mod)、Modifier.isStatic(mod)、Modifier.isFinal(mod)等:判断具体修饰符
// Modifier 示例:解析类和方法修饰符
Class<?> clazz = String.class;
int mods = clazz.getModifiers();
System.out.println(Modifier.isFinal(mods)); // true
System.out.println(Modifier.isPublic(mods)); // true
Method m = String.class.getMethod("length");
int methodMods = m.getModifiers();
System.out.println(Modifier.isPublic(methodMods)); // true
System.out.println(Modifier.toString(methodMods)); // public
3.8 泛型与 Type 体系
| 类型 | 示例 | 用途 |
|---|---|---|
ParameterizedType | List<String> | getActualTypeArguments() 获取泛型实参 |
TypeVariable | T、E | 泛型声明中的类型变量 |
WildcardType | ? extends Number | 通配符 |
GenericArrayType | T[] | 泛型数组 |
Class | String | 普通类/接口 |
// 泛型 Type 示例:获取 List<String> 的元素类型
class Container {
public List<String> names;
}
Field field = Container.class.getField("names");
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
Type[] args = pt.getActualTypeArguments();
System.out.println(args[0]); // class java.lang.String
System.out.println(pt.getRawType()); // interface java.util.List
}
3.9 参数信息:Parameter(Java 8+)
getParameters():获取方法/构造器的参数列表Parameter.getType()、Parameter.getAnnotations():参数类型和注解
// Parameter 示例:获取方法参数信息
Method method = String.class.getMethod("substring", int.class, int.class);
Parameter[] params = method.getParameters();
for (Parameter p : params) {
System.out.println(p.getName() + " : " + p.getType());
}
// 输出参数名与类型(若编译时保留参数名需 -parameters)
四、反射在 Spring Boot 中的基石作用
4.1 为什么说反射是 Spring 的基石
Spring 的 IoC(控制反转) 和 依赖注入(DI) 几乎全部依赖反射实现。没有反射,就无法在运行时根据配置或注解动态创建 Bean、注入依赖、执行 AOP 切面。
4.2 Spring 中反射的主要应用
| 场景 | 反射实现 |
|---|---|
| Bean 实例化 | Constructor.newInstance() 或 Objenesis 等创建实例 |
| 构造器注入 | 解析 @Autowired 构造器,constructor.newInstance(args) 传入依赖 |
| Setter 注入 | getDeclaredMethods() 找到 setter,method.invoke(bean, dep) |
| 字段注入 | getDeclaredFields() 找到带 @Autowired 的字段,field.set(bean, getBean(...)),并配合 setAccessible(true) |
| 自动装配 | 解析 @Configuration、@Bean、@ComponentScan 等,通过反射加载配置类 |
| AOP 代理 | 通过反射获取目标方法信息,构建代理逻辑 |
// ========== 1. Bean 实例化 ==========
// Spring 通过无参/有参构造反射创建 Bean
Constructor<?> ctor = UserService.class.getDeclaredConstructor();
Object bean = ctor.newInstance();
// ========== 2. 构造器注入 ==========
// 解析 @Autowired 构造器,从容器取依赖后 newInstance
Constructor<?> autowiredCtor = OrderService.class.getDeclaredConstructor(UserService.class);
Object userSvc = container.getBean(UserService.class); // 伪:从容器取
Object orderBean = autowiredCtor.newInstance(userSvc);
// ========== 3. Setter 注入 ==========
// 遍历方法,找到 setXxx,invoke 注入依赖
Object service = UserService.class.getDeclaredConstructor().newInstance();
for (Method m : UserService.class.getDeclaredMethods()) {
if (m.getName().startsWith("set") && m.getParameterCount() == 1) {
Class<?> paramType = m.getParameterTypes()[0];
Object dep = container.getBean(paramType); // 伪:从容器取
m.invoke(service, dep);
}
}
// ========== 4. 字段注入 ==========
// 扫描 @Autowired 字段,setAccessible 后 field.set
for (Field f : UserController.class.getDeclaredFields()) {
if (f.isAnnotationPresent(Autowired.class)) {
f.setAccessible(true);
Object dep = container.getBean(f.getType());
f.set(controller, dep);
}
}
// ========== 5. 自动装配(解析 @Configuration @Bean)==========
// 扫描配置类,调用 @Bean 方法得到 Bean 实例
Class<?> configClass = Class.forName("com.example.AppConfig");
for (Method m : configClass.getDeclaredMethods()) {
if (m.isAnnotationPresent(Bean.class)) {
Object configInstance = configClass.getDeclaredConstructor().newInstance();
Object bean = m.invoke(configInstance); // 调用 @Bean 方法
container.register(m.getReturnType(), bean);
}
}
// ========== 6. AOP 代理(反射获取目标方法)==========
// 在 InvocationHandler.invoke 中通过 Method 反射调用目标
InvocationHandler handler = (proxy, method, args) -> {
Method targetMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes());
return targetMethod.invoke(target, args); // 反射调用真实方法
};
4.3 Spring Boot 自动配置与反射
- 通过 SPI 读取
META-INF/spring.factories,利用反射加载外部 jar 中的配置类 @SpringBootApplication聚合@EnableAutoConfiguration、@ComponentScan等,反射扫描并注册 Bean- 核心效果:无需手写
new,由容器在运行时通过反射完成实例化与依赖注入
// 极简模拟:Spring 字段注入的反射实现(伪代码)
public Object createBean(Class<?> beanClass) throws Exception {
Object bean = beanClass.getDeclaredConstructor().newInstance();
for (Field field : beanClass.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
field.setAccessible(true);
Object dep = getBean(field.getType()); // 从容器取依赖
field.set(bean, dep);
}
}
return bean;
}
五、与反射密切相关的技术
5.1 动态代理
JDK 动态代理(基于接口):
- 使用
java.lang.reflect.Proxy与InvocationHandler - 代理类实现与目标类相同的接口
- 方法调用时触发
InvocationHandler.invoke(),在其中通过Method.invoke(target, args)调用真实方法 - 要求:目标类必须实现至少一个接口
CGLIB 动态代理(基于继承):
- 通过字节码生成目标类的子类
- 重写父类方法,加入增强逻辑
- 使用
MethodInterceptor,内部仍会通过反射或 FastClass 调用方法 - 限制:目标类和方法不能为
final
Spring AOP 选择规则:
- 有接口 → JDK 动态代理
- 无接口 → CGLIB
proxy-target-class=true→ 强制 CGLIB
// JDK 动态代理示例:在 invoke 中通过反射调用真实方法
interface UserService { void save(String name); }
class UserServiceImpl implements UserService {
public void save(String name) { System.out.println("保存: " + name); }
}
UserService target = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
(Object p, Method method, Object[] args) -> {
System.out.println("前置增强");
Object ret = method.invoke(target, args); // 反射调用目标方法
System.out.println("后置增强");
return ret;
}
);
proxy.save("张三"); // 输出:前置增强 / 保存: 张三 / 后置增强
5.2 注解处理
- 注解需
@Retention(RetentionPolicy.RUNTIME)才能在运行时被反射读取 AnnotatedElement接口(Class、Method、Field 等均实现)提供:getAnnotation(Class):获取指定注解isAnnotationPresent(Class):是否存在该注解getDeclaredAnnotations():获取所有注解
- 自定义框架(如分布式锁、权限校验)常通过反射扫描注解,实现声明式编程
// 注解反射示例:扫描带 @RequestMapping 的方法
@Retention(RetentionPolicy.RUNTIME)
@interface RequestMapping { String value(); }
class UserController {
@RequestMapping("/user/list")
public void list() {}
}
for (Method m : UserController.class.getDeclaredMethods()) {
if (m.isAnnotationPresent(RequestMapping.class)) {
RequestMapping rm = m.getAnnotation(RequestMapping.class);
System.out.println("映射: " + rm.value() + " -> " + m.getName());
// 输出:映射: /user/list -> list
}
}
5.3 ORM 与序列化
- MyBatis:通过反射将 ResultSet 列映射到实体属性(
Field.set()或 setter),并用Reflector缓存元信息提升性能 - Jackson / Gson:通过反射解析字段类型与注解,完成 JSON 序列化/反序列化
// ORM 风格示例:ResultSet 反射填充实体(简化版)
// 模拟从 DB 行 {id=1, name="test"} 填充到 User 对象
public <T> T mapRow(ResultSet rs, Class<T> clazz) throws Exception {
Object bean = clazz.getDeclaredConstructor().newInstance();
ResultSetMetaData meta = rs.getMetaData();
for (int i = 1; i <= meta.getColumnCount(); i++) {
String colName = meta.getColumnLabel(i);
Field field = clazz.getDeclaredField(colName); // 列名与字段名一致
field.setAccessible(true);
field.set(bean, rs.getObject(i));
}
return (T) bean;
}
5.4 类加载与 ClassLoader
Class.forName()和ClassLoader.loadClass()都依赖 ClassLoader 加载字节码- 反射所操作的 Class 对象,由 ClassLoader 在类加载阶段创建并缓存在方法区