Java 反射机制详解及示例
什么是反射?
反射(Reflection)是 Java 在运行时动态获取类信息并操作类属性和方法的能力。通过反射,我们可以在程序运行时:
- 获取任意类的完整信息(类名、包名、父类、接口等)
- 创建对象(即使类名在编译时未知)
- 访问和修改字段(包括私有字段)
- 调用方法(包括私有方法)
- 动态处理数组
核心类
反射 API 主要位于 java.lang.reflect
包中:
Class
:类的元数据Field
:类的字段/属性Method
:类的方法Constructor
:类的构造方法Modifier
:访问修饰符的解析
基础操作示例
1. 获取 Class 对象的三种方式
// 方式1:类名.class
Class<String> stringClass = String.class;
// 方式2:对象.getClass()
String s = "Hello";
Class<?> stringClass2 = s.getClass();
// 方式3:Class.forName()(最常用)
Class<?> stringClass3 = Class.forName("java.lang.String");
2. 创建对象实例
// 使用默认构造函数
Class<?> clazz = Class.forName("java.util.Date");
Date date = (Date) clazz.newInstance(); // 注意:此方法JDK9已过时
// 使用带参数构造器(推荐)
Class<?> clazz = Class.forName("java.awt.Point");
Constructor<?> constructor = clazz.getConstructor(int.class, int.class);
Object point = constructor.newInstance(10, 20);
System.out.println(point); // 输出:java.awt.Point[x=10,y=20]
高级操作示例
3. 访问私有字段 & 修改值
class Secret {
private String secretCode = "ABC123";
}
public class Main {
public static void main(String[] args) throws Exception {
Secret obj = new Secret();
// 获取私有字段
Field field = Secret.class.getDeclaredField("secretCode");
field.setAccessible(true); // 关键:解除私有访问限制
// 读取值
String value = (String) field.get(obj);
System.out.println("原始值: " + value); // 输出:ABC123
// 修改值
field.set(obj, "NEW_CODE");
System.out.println("修改后: " + field.get(obj)); // 输出:NEW_CODE
}
}
4. 调用私有方法
class Calculator {
private int add(int a, int b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) throws Exception {
Calculator calc = new Calculator();
// 获取私有方法
Method method = Calculator.class.getDeclaredMethod("add", int.class, int.class);
method.setAccessible(true); // 解除私有访问
// 调用方法
int result = (int) method.invoke(calc, 5, 3);
System.out.println("计算结果: " + result); // 输出:8
}
}
5. 动态代理(反射高级应用)
interface Speaker {
void speak(String message);
}
class RealSpeaker implements Speaker {
public void speak(String msg) {
System.out.println("说: " + msg);
}
}
public class Main {
public static void main(String[] args) {
Speaker real = new RealSpeaker();
// 创建动态代理
Speaker proxy = (Speaker) Proxy.newProxyInstance(
Speaker.class.getClassLoader(),
new Class[]{Speaker.class},
(proxyObj, method, argsArray) -> {
System.out.println("---前置处理---");
Object result = method.invoke(real, argsArray);
System.out.println("---后置处理---");
return result;
}
);
proxy.speak("你好世界");
/* 输出:
---前置处理---
说: 你好世界
---后置处理---
*/
}
}
使用场景
- 框架开发:Spring(依赖注入)、Hibernate(ORM映射)
- 动态代理:AOP编程
- 注解处理:运行时解析注解
- 工具开发:IDE代码提示、调试工具
- 泛型擦除:绕过泛型限制(如
List<Integer>
中插入String)
注意事项
- 性能开销:反射操作比常规代码慢10-100倍(通过
setAccessible(true)
可部分优化) - 安全限制:需处理
SecurityException
- 破坏封装:可访问私有成员,破坏面向对象特性
- 代码复杂度:错误处理较繁琐
完整综合示例
import java.lang.reflect.*;
class Person {
private String name;
private int age;
public Person() {}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
private String getInfo() {
return name + "(" + age + ")";
}
}
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
// 1. 获取Class对象
Class<?> clazz = Class.forName("Person");
// 2. 创建对象(两种方式)
Object obj1 = clazz.newInstance();
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object obj2 = constructor.newInstance("张三", 25);
// 3. 访问私有字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj2, "李四");
// 4. 调用私有方法
Method method = clazz.getDeclaredMethod("getInfo");
method.setAccessible(true);
String info = (String) method.invoke(obj2);
System.out.println("人员信息: " + info); // 输出:李四(25)
// 5. 获取类结构信息
System.out.println("\n类结构信息:");
System.out.println("类名: " + clazz.getSimpleName());
System.out.println("字段列表:");
for (Field f : clazz.getDeclaredFields()) {
System.out.println(" " + Modifier.toString(f.getModifiers()) + " " +
f.getType().getSimpleName() + " " + f.getName());
}
}
}
输出结果:
人员信息: 李四(25)
类结构信息:
类名: Person
字段列表:
private String name
private int age
通过以上示例,可以清晰了解反射的核心操作。在实际开发中,应谨慎使用反射,优先考虑常规编程方式,仅在需要突破语言限制或开发框架时使用。