Java反射机制允许程序在运行时获取类的元信息并动态操作对象,这种能力为框架开发、动态代理等场景提供了强大的技术支持。本文将深入解析Java反射的核心概念与应用。
一、反射机制是java里动态操作类的秘密武器
简单思考三个问题:
- 在spring开发中,在类上添加@Service或@Component等注解,使用时直接注入这个类的对象就可以调用,并不会报错空指针,why?
- 为什么mybatis框架中,我们定义一个接口(interface),且没有实现类,使用时直接注入这个接口类的对象就可以调用,并不会报错空指针而且还有实现逻辑,why?
- 在方法上加上@Transaction,能在调用时判断是否需要开启事务,why?
二、类的元数据
在java基础里,有详细介绍类、方法、字段(成员变量),以及很多修饰符:public、protected、static、private、注解等等,不做赘述。这里通过E-R图(实体关系)来描述类的元数据里的抽象世界。
2.1 Class对象
每个类在JVM中都对应一个Class对象,可通过三种方式获取:
Class<?> clazz1 = String.class;
Class<?> clazz2 = Class.forName("java.lang.String");
Class<?> clazz3 = "".getClass();
2.2 成员变量
// 获取所有public字段(包括继承)
Field[] publicFields = clazz.getFields();
// 获取所有字段(包括私有)
Field[] allFields = clazz.getDeclaredFields();
// 获取指定字段
Field nameField = clazz.getDeclaredField("name");
2.3 方法操作
// 获取public方法(包含继承)
Method[] publicMethods = clazz.getMethods();
// 获取所有声明方法
Method[] allMethods = clazz.getDeclaredMethods();
// 获取指定方法
Method method = clazz.getDeclaredMethod("calculate", int.class, double.class);
2.4 方法参数
Parameter[] parameters = method.getParameters();
for (Parameter param : parameters) {
System.out.println(param.getName() + ": " + param.getType());
}
2.5 注解处理
// 类注解
Annotation[] classAnnotations = clazz.getAnnotations();
// 字段注解
Field field = clazz.getDeclaredField("name");
MyAnnotation fieldAnnotation = field.getAnnotation(MyAnnotation.class);
// 方法注解
Method method = clazz.getMethod("toString");
Annotation[] methodAnnotations = method.getAnnotations();
三、反射创建实例
3.1.无参构造(已过时)
User user = (User) clazz.newInstance();
3.2 推荐构造器方式
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object instance = constructor.newInstance("John", 30);
四、动态操作对象
4.1 修改字段值
User user = new User();
Field nameField = User.class.getDeclaredField("name");
nameField.setAccessible(true); // 突破私有访问限制
nameField.set(user, "Alice");
4.2 执行方法
Method method = User.class.getDeclaredMethod("setName", String.class);
method.invoke(user, "Bob");
// 私有方法调用
Method privateMethod = User.class.getDeclaredMethod("internalProcess");
privateMethod.setAccessible(true);
privateMethod.invoke(user);
五、主流反射工具类
5.1 Apache Commons Lang
// 快速创建实例
User user = ConstructorUtils.invokeConstructor(User.class, "param");
// 简化方法调用
MethodUtils.invokeMethod(user, "setName", "Charlie");
5.2 Spring 框架
// 安全处理反射异常
ReflectionUtils.doWithFields(User.class, field -> {
field.setAccessible(true);
// 字段处理逻辑
});
// 方法回调
ReflectionUtils.doWithMethods(User.class, method -> {
// 方法过滤处理
});
六、反射的应用与注意事项
典型应用场景:
- 框架设计(如Spring IOC)
- 动态代理(AOP实现)
- 序列化/反序列化
- 单元测试框架
七、结语
以上是java反射所有基本概念和详细的语法使用案例,在框架设计中一般不单独使用,主要结合注解以及动态代理,实现自动化的封装逻辑,把业务逻辑和底层技术逻辑彻底解耦。后续会逐一讲述注解、动态代理的实际项目实战应用,欢迎点赞关注+收藏。