Java反射与动态代理,面试必问底层原理一次讲透

发布时间:2026/9/14 23:25:19
Java反射与动态代理,面试必问底层原理一次讲透 面试Java高级岗反射和动态代理几乎是必考题。很多人能背出API但一问底层就卡壳。其实这两块是Spring、MyBatis等框架的基石理解透了很多框架源码自然就通了。一、反射运行时的类信息探针反射的核心是Class对象。类加载后JVM在方法区生成一个描述该类的运行时数据结构Class就是访问这个结构的入口。获取Class有三种方式类名.class、对象.getClass()、Class.forName(全限定名)。第三种最常用因为可以在运行时动态加载。拿到Class后就能获取Method、Field、Constructor。调用method.invoke(obj, args)时底层并不是直接执行方法。JVM会先做方法查找、权限检查再把参数包装成Object[]。真正的调用委托给MethodAccessor首次调用走Native实现之后JVM会动态生成一个字节码类如GeneratedMethodAccessor1直接调用目标方法。所以反射慢主要慢在查找、安全检查、参数装箱和无法内联。setAccessible(true)可以关闭安全检查性能提升明显。反射是Spring IOC的根基。BeanDefinition里的类名就是通过Class.forName加载再反射实例化、注入依赖。MyBatis的Mapper接口没有实现类也是靠JDK动态代理生成代理对象把方法调用转成SQL执行。二、动态代理运行期生成代理类动态代理解决的是“不修改源码增强方法”的问题。Java有两种实现。JDK动态代理基于接口。核心是Proxy.newProxyInstance和InvocationHandler。调用时ProxyGenerator会在内存生成一个$Proxy0类它继承Proxy并实现目标接口。所有接口方法都转发到InvocationHandler.invoke在invoke里通过反射调用目标方法并插入增强逻辑。为什么必须基于接口因为生成的代理类已经继承了ProxyJava单继承没法再继承目标类。CGLIB基于继承。它用ASM字节码框架生成目标类的子类方法拦截走MethodInterceptor。CGLIB的FastClass机制为每个方法建立索引调用时直接按索引定位避免了反射性能更高。但无法代理final类和方法。Spring AOP的选择策略目标类有接口默认用JDK没有则用CGLIB。Spring Boot 2.x后默认全部用CGLIB因为性能更好且能代理无接口类。三、面试高频追问反射为什么慢方法查找、访问检查、参数装箱、JIT无法内联。优化手段缓存Class和Method对象setAccessible(true)或者用MethodHandle、LambdaMetafactory替代。JDK代理和CGLIB区别JDK基于接口生成类实现接口CGLIB基于继承生成子类。JDK反射调用CGLIB用FastClass索引调用。CGLIB不能代理final。动态代理底层字节码JDK用ProxyGenerator生成字节码CGLIB用ASM。生成的代理类在运行期存在于内存可以通过-Dsun.misc.ProxyGenerator.saveGeneratedFilestrue导出查看。总结反射是“看透类”动态代理是“伪装类”。反射让框架能动态创建对象、调用方法动态代理让框架能在不侵入业务的前提下增强逻辑。面试时能讲清MethodAccessor的委托机制、$Proxy0的生成结构、FastClass的索引原理基本就能和其他候选人拉开差距。底层原理并不神秘拆开看都是类加载、字节码和反射调用的组合。