Java反射机制详解
·
什么是反射?
反射(Reflection) 是Java的一种强大特性,允许程序在运行时动态地获取类的信息(方法、字段、构造器等),并能动态调用对象的方法、访问字段。
通俗理解:把Java类当作"对象"来操作。
核心类
| 类 | 作用 |
|---|---|
Class |
代表一个类或接口 |
Constructor |
代表构造方法 |
Method |
代表成员方法 |
Field |
代表成员变量 |
获取Class对象的三种方式
java
// 方式1:通过类名.class
Class<?> clazz1 = String.class;
// 方式2:通过对象的getClass()
String s = "hello";
Class<?> clazz2 = s.getClass();
// 方式3:通过Class.forName()(最常用)
Class<?> clazz3 = Class.forName("java.lang.String");
反射能做什么?
1. 获取类的信息
java
Class<?> clazz = Class.forName("java.util.ArrayList");
// 获取类名
System.out.println("类名:" + clazz.getName());
// 获取所有public方法
Method[] methods = clazz.getMethods();
for (Method m : methods) {
System.out.println(m.getName());
}
// 获取所有字段
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
System.out.println(f.getName() + " : " + f.getType());
}
2. 动态创建对象
java
// 调用无参构造器
Class<?> clazz = Class.forName("java.util.ArrayList");
Object obj = clazz.newInstance(); // 已废弃,推荐下面的方式
// 推荐方式
Constructor<?> constructor = clazz.getConstructor();
Object obj2 = constructor.newInstance();
3. 动态调用方法
java
Class<?> clazz = Class.forName("java.lang.String");
Object str = clazz.getConstructor(String.class).newInstance("Hello");
// 调用length()方法
Method method = clazz.getMethod("length");
int length = (int) method.invoke(str);
System.out.println(length); // 输出 5
// 调用substring(int, int)
Method subMethod = clazz.getMethod("substring", int.class, int.class);
String result = (String) subMethod.invoke(str, 1, 4);
System.out.println(result); // 输出 "ell"
4. 访问/修改私有字段
java
class User {
private String name = "默认";
}
User user = new User();
Class<?> clazz = user.getClass();
Field field = clazz.getDeclaredField("name");
// 突破private限制(暴力反射)
field.setAccessible(true);
// 读取
String name = (String) field.get(user);
System.out.println(name); // 默认
// 修改
field.set(user, "反射修改");
System.out.println(field.get(user)); // 反射修改
常见应用场景
| 场景 | 说明 |
|---|---|
| 框架(Spring、MyBatis) | 动态创建Bean、注入依赖 |
| 注解处理器 | 运行时读取注解并执行逻辑 |
| 动态代理 | JDK动态代理基于反射 |
| IDE自动提示 | 运行时获取类结构信息 |
| 单元测试(JUnit) | 动态执行测试方法 |
性能与注意事项
-
⚠️ 反射有性能开销(比直接调用慢),不宜在热点代码中频繁使用
-
⚠️
setAccessible(true)破坏了封装性,需谨慎使用 -
✅ 反射是框架底层的基础,理解它有助于深入理解Java生态
完整示例代码
java
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
// 1. 获取Class
Class<?> clazz = Class.forName("java.lang.String");
// 2. 获取构造器创建对象
Constructor<?> constructor = clazz.getConstructor(String.class);
Object str = constructor.newInstance("Reflection");
// 3. 调用方法
Method method = clazz.getMethod("toUpperCase");
Object result = method.invoke(str);
System.out.println(result); // REFLECTION
// 4. 获取所有方法名
System.out.println("\n=== String所有方法 ===");
for (Method m : clazz.getDeclaredMethods()) {
System.out.println(m.getName());
}
}
}
小结
| 核心要点 | 一句话总结 |
|---|---|
| 反射是什么 | 运行时动态操作类和对象 |
| 关键类 | Class、Constructor、Method、Field |
| 核心操作 | 创建对象、调用方法、访问字段 |
| 主要用途 | 框架底层、注解处理、动态代理 |
| 注意事项 | 有性能开销,慎用暴力反射 |
更多推荐
所有评论(0)