615 字
2 分钟
Java反射机制详解
反射是Java高级特性中最让我着迷的一个——运行时能看见自己,还能修改自己。工作中用Spring的依赖注入时一直在想它是怎么做到的,后来才明白反射就是那个幕后推手。这篇文章把反射的用法和原理讲清楚,看完你也能写出自己的框架。
Java反射机制详解
什么是反射?
反射就是程序在运行时能获取自己的信息——有哪些类、哪些方法、哪些字段,还能动态调用它们。我第一次用反射的时候感觉像在写黑科技,原来代码能看见自己长什么样。
反射的应用场景
- 框架开发:Spring、Hibernate等框架的核心机制
- 动态代理:AOP(面向切面编程)的基础
- 序列化/反序列化:JSON、XML转换
- 插件系统:动态加载类
- 配置文件解析:根据配置动态加载类
获取Class对象
反射的入口,有三种方式:
// 1. 类名.classClass<?> clazz = String.class;
// 2. 对象.getClass()String str = "Hello";Class<?> clazz = str.getClass();
// 3. Class.forName()(最常用,因为可以动态指定类名)Class<?> clazz = Class.forName("java.lang.String");核心操作
获取类信息
Class<?> clazz = Person.class;clazz.getName(); // 全限定名clazz.getSimpleName(); // 简单类名clazz.getModifiers(); // 修饰符clazz.getSuperclass(); // 父类clazz.getInterfaces(); // 实现的接口获取构造方法并创建实例
// 获取构造方法Constructor<?> constructor = clazz.getConstructor(String.class, int.class);// 创建实例Object instance = constructor.newInstance("张三", 25);
// 调用无参构造(Java 9+已弃用newInstance())Object instance = clazz.getDeclaredConstructor().newInstance();获取方法并调用
Method method = clazz.getMethod("methodName", String.class);Object result = method.invoke(instance, "参数");
// 调用私有方法Method privateMethod = clazz.getDeclaredMethod("privateMethod");privateMethod.setAccessible(true); // 重要!跳过访问检查privateMethod.invoke(instance);获取字段并读写
Field field = clazz.getDeclaredField("name");field.setAccessible(true); // 私有字段需要这个
// 读取String name = (String) field.get(instance);
// 写入field.set(instance, "李四");动态代理
反射在动态代理中的经典应用——AOP的基础:
// 接口interface UserService { void addUser(String name);}
// 实现class UserServiceImpl implements UserService { public void addUser(String name) { System.out.println("添加用户:" + name); }}
// InvocationHandlerclass LogHandler implements InvocationHandler { private Object target;
public LogHandler(Object target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始执行:" + method.getName()); Object result = method.invoke(target, args); System.out.println("执行完毕:" + method.getName()); return result; }}
// 使用UserService userService = new UserServiceImpl();UserService proxy = (UserService) Proxy.newProxyInstance( userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new LogHandler(userService));proxy.addUser("张三");性能优化
反射比直接调用慢,因为需要在运行时解析类型信息。不过大部分场景下这点性能损耗可以忽略,除非是在高并发的热点路径上。
优化方法:
- 缓存反射对象——Method、Field等获取后缓存起来重用
- setAccessible(true)——跳过访问权限检查
- 用MethodHandle(Java 7+)——比反射更高效
// 缓存Method对象private static final Method METHOD;
static { try { METHOD = SomeClass.class.getDeclaredMethod("someMethod"); METHOD.setAccessible(true); } catch (Exception e) { throw new RuntimeException(e); }}常见陷阱
- ClassNotFoundException——类名拼写错误
- NoSuchMethodException——方法名或参数类型不对
- IllegalAccessException——忘了setAccessible(true)
- InvocationTargetException——被调用的方法内部抛了异常
- 性能问题——热点路径上别用反射
💡 实战贴士: 反射虽然强大,但能不用就不用。如果只是为了获取某个类的信息,优先考虑用接口或抽象类来设计。框架和工具类里用反射是合理的,但业务代码里用反射就要小心了——代码可读性差、编译时检查不到、出了问题不好排查。
分享
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时
相关文章 智能推荐
1
Java注解详解
Java 刚学Java时觉得注解不就是几个@符号嘛,后来用Spring Boot才发现注解能玩出这么多花样——从编译检查到运行时注入,注解远不止看起来那么简单。
2
Java NIO详解
Java NIO的Selector模型让我第一次感受到了单线程处理万级连接的魅力。相比传统IO的阻塞读写,Channel加Buffer的组合简直是为高性能网络编程量身定做。
3
Java异常处理详解
Java try-catch是Java最基础的异常处理手段,但什么时候该用受检异常、什么时候该抛RuntimeException,这中间有不少门道值得琢磨。
4
Java单元测试详解
Java 单元测试曾经是我最懒得写的代码,直到被线上bug教育了几次之后才老老实实补上。JUnit配合Mockito,写测试也可以很愉快。
5
Java集合框架详解
Java Java集合框架的源码翻来覆去看了好几遍,每次看都有新收获。从ArrayList到ConcurrentHashMap,每个集合背后都有精妙的设计思想。






