反射是 Java 提供的一种强大机制,允许程序在运行时(Runtime)动态地获取类的信息、操作类的属性和方法。这种能力使得 Java 程序可以突破编译时的限制,实现更灵活的设计。
一、反射的核心概念
1. 什么是反射
反射是指在程序运行时动态地:
-
获取类的完整结构(类名、方法、属性、构造器等)
-
创建对象
-
调用方法
-
访问/修改字段值
2. 反射的核心类
-
Class
:代表类的实体 -
Field
:代表类的成员变量 -
Method
:代表类的方法 -
Constructor
:代表类的构造方法
二、反射的基本使用
1. 获取Class对象的三种方式
// 1. 通过类名.class
Class<?> clazz1 = String.class;
// 2. 通过对象.getClass()
String str = "Hello";
Class<?> clazz2 = str.getClass();
// 3. 通过Class.forName()(最常用)
Class<?> clazz3 = Class.forName("java.lang.String");
2. 创建对象
Class<?> clazz = Class.forName("com.example.User");
// 使用无参构造
Object obj1 = clazz.newInstance(); // 已过时,推荐使用下面的方式
Object obj2 = clazz.getDeclaredConstructor().newInstance();
// 使用有参构造
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object obj3 = constructor.newInstance("张三", 25);
3. 调用方法
Class<?> clazz = Class.forName("com.example.Calculator");
Object calculator = clazz.newInstance();
// 获取方法
Method addMethod = clazz.getMethod("add", int.class, int.class);
// 调用方法
Object result = addMethod.invoke(calculator, 10, 20);
System.out.println("结果: " + result); // 输出: 结果: 30
4. 访问字段
Class<?> clazz = Class.forName("com.example.Person");
Object person = clazz.newInstance();
// 获取字段(包括私有字段)
Field nameField = clazz.getDeclaredField("name");
// 设置可访问(即使是private字段)
nameField.setAccessible(true);
// 设置字段值
nameField.set(person, "李四");
// 获取字段值
String name = (String) nameField.get(person);
System.out.println(name); // 输出: 李四
三、反射的应用场景
-
框架设计:Spring、Hibernate等框架大量使用反射
-
Spring的IoC容器通过反射创建和管理Bean
-
Hibernate通过反射实现ORM映射
-
-
动态代理:AOP编程的基础
-
注解处理:运行时通过反射读取注解信息
-
工具类开发:如通用的对象属性拷贝工具
-
IDE功能:代码提示、自动补全等功能使用反射获取类信息
四、反射的优缺点
优点:
-
灵活性高:可以在运行时动态操作类和对象
-
扩展性强:可以实现通用框架和组件
-
突破访问限制:可以访问私有成员
缺点:
-
性能开销:反射操作比直接调用慢
-
安全问题:可以绕过访问权限检查
-
代码复杂度:反射代码可读性较差
-
破坏封装性:可以访问私有成员,破坏面向对象特性
五、性能优化建议
-
缓存Class对象:避免重复获取
-
缓存Method/Field对象:避免重复查找
-
setAccessible(true)只调用一次
-
考虑使用MethodHandle(Java7+)
六、反射与泛型
通过反射可以绕过泛型检查:
List<String> list = new ArrayList<>();
list.add("hello");
Class<?> clazz = list.getClass();
Method addMethod = clazz.getMethod("add", Object.class);
addMethod.invoke(list, 100); // 添加非String类型
System.out.println(list); // 输出: [hello, 100]
反射是Java高级特性中的重要部分,合理使用可以极大增强程序的灵活性,但也要注意其带来的性能和安全问题。