Java进阶——反射机制超全详解
反射能在运行时动态操作类和对象的能力,极大地增强了程序的灵活性。但是反射的使用也伴随着性能开销和安全风险。本文将由博主带你一起深入探讨 Java 反射的核心概念、关键类和方法,以及在日常开发中的应用场景。
本文目录
- 一、反射的核心概念
- 1. 运行时类型信息
- 2. 核心类
- 二、获取 Class 对象的四种方式
- 1. 类名.class
- 2. 对象.getClass()
- 3. Class.forName()
- 4. 类加载器获取
- 三、反射操作字段
- 1. 获取字段
- 2. 访问私有字段
- 3. 修改字段值
- 四、反射调用方法
- 1. 获取方法
- 2. 方法调用
- 3. 静态方法调用
- 五、反射操作构造方法
- 1. 创建对象实例
- 2. 突破单例模式
- 六、反射性能优化
- 1. 缓存反射对象
- 2. 避免频繁反射调用
- 七、反射在日常工作中的实际应用场景
- 1. 动态加载插件
- 2. 单元测试工具
- 总结
一、反射的核心概念
1. 运行时类型信息
反射允许在运行时获取类的完整结构,包括类名、方法、字段、注解等,并动态操作对象,突破编译时的类型限制。
2. 核心类
Class<T>
:类的元数据入口,是所有反射操作的起点。Field
:代表类的字段信息,可用于获取和设置字段的值。Method
:代表类的方法信息,可用于调用类的方法。Constructor<T>
:代表类的构造方法信息,可用于创建对象实例。Modifier
:用于解析访问修饰符,如public
、private
等。
二、获取 Class 对象的四种方式
1. 类名.class
适用于编译时已知类的情况。
Class<User> clazz = User.class;
2. 对象.getClass()
通过对象实例获取其对应的 Class
对象。
User user = new User();
Class<?> clazz = user.getClass();
3. Class.forName()
通过类的全限定名动态加载类,需要处理 ClassNotFoundException
。
Class<?> clazz = Class.forName("com.shop.ecommerce.User");
4. 类加载器获取
在模块化环境中,可使用类加载器加载类。
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> clazz = loader.loadClass("com.shop.ecommerce.User");
三、反射操作字段
1. 获取字段
getField(String name)
:仅获取公共字段(包括继承的)。getDeclaredField(String name)
:获取本类声明的所有字段(包括private
)。
2. 访问私有字段
Field field = clazz.getDeclaredField("字段名");
field.setAccessible(true); // 设置是否可以访问 private
String value = (String) field.get(user);
3. 修改字段值
field.set(user, "newValue");
四、反射调用方法
1. 获取方法
getMethod(String name, Class<?>... paramTypes)
:获取公共方法(含继承)。getDeclaredMethod(...)
:获取本类声明的所有方法。
// 获取 User 类的私有方法
Method method = clazz.getDeclaredMethod("方法名", int.class);
method.setAccessible(true);
2. 方法调用
Object result = method.invoke(user, 100); // 参数需严格匹配
3. 静态方法调用
Method staticMethod = clazz.getMethod("getDefaultRole");
String role = (String) staticMethod.invoke(null); // 实例参数传 null
五、反射操作构造方法
1. 创建对象实例
Constructor<User> constructor = clazz.getConstructor(String.class, String.class);
User user = constructor.newInstance("user123", "VIP");
2. 突破单例模式
// 反射调用私有构造方法
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton instance = constructor.newInstance();
六、反射性能优化
1. 缓存反射对象
private static final Method calculateDiscountMethod;
static {
try {
calculateDiscountMethod = User.class.getDeclaredMethod("calculateDiscount", int.class);
calculateDiscountMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
2. 避免频繁反射调用
反射比直接调用慢 10 - 100 倍,应尽量减少反射调用的频率。
七、反射在日常工作中的实际应用场景
1. 动态加载插件
// 加载支付插件
Class<?> paymentClass = Class.forName("com.shop.payment.AlipayPlugin");
PaymentPlugin plugin = (PaymentPlugin) paymentClass.newInstance();
plugin.process(order);
2. 单元测试工具
// 测试私有方法
public class OrderServiceTest {
@Test
void testPrivateMethod() throws Exception {
Method method = OrderService.class.getDeclaredMethod("validateStock", Long.class);
method.setAccessible(true);
boolean result = (boolean) method.invoke(orderService, 1001L);
assertTrue(result);
}
}
总结
合理使用反射可以实现插件化架构、灵活的数据处理。
← 上一篇 Java进阶——Stream流以及常用方法详解 |
记得点赞、关注、收藏哦!
| 下一篇 Java进阶——注解一文全懂 → |