Java 反射机制深度笔记
一、反射基础:Class 类
1. Class 对象的获取方式
获取方式 | 代码示例 | 适用场景 |
---|
类名.class | Class<User> clazz = User.class; | 编译时已知类名 |
对象.getClass() | user.getClass(); | 已有对象实例 |
Class.forName() | Class.forName("com.example.User"); | 动态加载类 |
类加载器 | ClassLoader.loadClass("com.example.User"); | 自定义类加载 |
2. Class 类核心方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Constructor<?>[] getConstructors(); Constructor<T> getConstructor(Class<?>... parameterTypes);
Field getField(String name); Field getDeclaredField(String name);
Method getMethod(String name, Class<?>... parameterTypes); Method getDeclaredMethod(String name, Class<?>... parameterTypes);
T newInstance(); Constructor.newInstance(Object... initargs);
|
3. 类型检查方法
1 2 3 4 5
| isInterface() isArray() isEnum() isPrimitive() isAnnotationPresent(Class<? extends Annotation> annotationClass)
|
二、反射操作实践
1. 字段操作示例
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ReflectFieldDemo { public static void main(String[] args) throws Exception { User user = new User("张三", 25); Class<?> clazz = user.getClass(); Field ageField = clazz.getDeclaredField("age"); ageField.setAccessible(true); ageField.setInt(user, 30); System.out.println(user); } }
|
2. 方法调用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class ReflectMethodDemo { public static void main(String[] args) throws Exception { Class<User> clazz = User.class; User user = clazz.getConstructor(String.class, int.class) .newInstance("李四", 28); Method method = clazz.getDeclaredMethod("privateMethod", String.class); method.setAccessible(true); Object result = method.invoke(user, "参数"); System.out.println("方法返回值: " + result); } }
|
3. 构造方法实例化对比
方式 | 代码示例 | 特点 |
---|
newInstance() | User user = User.class.newInstance(); | 只能调用无参构造,已废弃 |
Constructor | Constructor<User> c = User.class.getConstructor(String.class, int.class);<br>User user = c.newInstance("王五", 30); | 推荐方式,支持有参构造 |
三、动态代理机制
1. JDK 动态代理
特点:
- 基于接口实现
java.lang.reflect.Proxy
生成代理类- 需要实现
InvocationHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class JdkProxyDemo { public static void main(String[] args) { UserService realService = new UserServiceImpl(); UserService proxy = (UserService) Proxy.newProxyInstance( realService.getClass().getClassLoader(), realService.getClass().getInterfaces(), (proxy1, method, args1) -> { System.out.println("前置处理"); Object result = method.invoke(realService, args1); System.out.println("后置处理"); return result; }); proxy.addUser("test"); } }
|
2. CGLIB 动态代理
特点:
- 基于类继承
- 不需要接口
- Spring AOP 默认使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class CglibProxyDemo { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> { System.out.println("CGLIB前置处理"); Object result = proxy.invokeSuper(obj, args1); System.out.println("CGLIB后置处理"); return result; }); UserService proxy = (UserService) enhancer.create(); proxy.addUser("test"); } }
|
3. 两种代理对比
特性 | JDK 动态代理 | CGLIB 代理 |
---|
代理方式 | 接口实现 | 类继承 |
依赖 | 无需额外库 | 需要cglib库 |
性能 | 调用快,创建慢 | 创建快,调用稍慢 |
限制 | 必须实现接口 | 不能代理final类/方法 |
适用场景 | 接口明确的场景 | 无接口或需要高性能 |
四、注解解析技术
1. 运行时注解处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyAnnotation { String value() default ""; int priority() default 0; }
public class AnnotationProcessor { public static void processAnnotations(Object obj) { Class<?> clazz = obj.getClass(); for (Method method : clazz.getDeclaredMethods()) { if (method.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation annotation = method.getAnnotation(MyAnnotation.class); System.out.println("发现注解方法: " + method.getName()); System.out.println("注解值: " + annotation.value()); System.out.println("优先级: " + annotation.priority()); } } } }
|
2. Spring 风格注解解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Autowired { }
public class DIContainer { public static <T> T getInstance(Class<T> clazz) throws Exception { T instance = clazz.getDeclaredConstructor().newInstance(); for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(Autowired.class)) { Object fieldInstance = getInstance(field.getType()); field.setAccessible(true); field.set(instance, fieldInstance); } } return instance; } }
|
3. 编译时注解处理(APT)
定义注解处理器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @SupportedAnnotationTypes("com.example.MyAnnotation") @SupportedSourceVersion(SourceVersion.RELEASE_11) public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (Element element : roundEnv.getElementsWithAnnotation(MyAnnotation.class)) { if (element.getKind() == ElementKind.METHOD) { ExecutableElement method = (ExecutableElement) element; String methodName = method.getSimpleName().toString(); processingEnv.getMessager().printMessage( Diagnostic.Kind.NOTE, "发现注解方法: " + methodName); } } return true; } }
|
注册处理器(META-INF/services/javax.annotation.processing.Processor)
五、反射性能优化
1. 缓存反射对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class ReflectionCache { private static final Map<Class<?>, Method> methodCache = new ConcurrentHashMap<>(); public static Object invokeMethod(Object obj, String methodName, Object... args) throws Exception { Class<?> clazz = obj.getClass(); Method method = methodCache.computeIfAbsent(clazz, c -> Arrays.stream(c.getDeclaredMethods()) .filter(m -> m.getName().equals(methodName)) .findFirst() .orElseThrow()); method.setAccessible(true); return method.invoke(obj, args); } }
|
2. MethodHandle(Java 7+)
1 2 3 4 5 6 7 8 9 10 11
| public class MethodHandleDemo { public static void main(String[] args) throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodType type = MethodType.methodType(void.class, String.class); MethodHandle handle = lookup.findVirtual(User.class, "setName", type); User user = new User(); handle.invokeExact(user, "张三"); System.out.println(user.getName()); } }
|
3. 性能对比(纳秒级操作)
操作方式 | 首次调用 | 缓存后调用 | MethodHandle |
---|
直接调用 | 2-5 ns | - | - |
反射调用 | 1000-2000 ns | 500-1000 ns | 50-100 ns |
六、安全注意事项
权限控制:
1 2 3 4 5
| SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new ReflectPermission("suppressAccessChecks")); }
|
防御措施:
- 限制反射可访问的包路径
- 对敏感方法添加额外权限检查
- 使用
setAccessible()
后及时恢复原状态
最佳实践:
1 2 3 4 5 6 7 8
| Field field = clazz.getDeclaredField("secret"); boolean accessible = field.isAccessible(); try { field.setAccessible(true); } finally { field.setAccessible(accessible); }
|
七、典型应用场景
框架开发:
- Spring IOC 容器
- JPA/Hibernate ORM 映射
- JUnit 测试框架
动态功能:
工具类:
- BeanUtils 属性拷贝
- 通用DAO实现
- 动态SQL生成
通过合理使用反射机制,可以实现高度灵活的系统架构,但需要注意性能开销和安全风险。