反射是让java程序在运行时能动态感知并操作类结构的能力,核心是class对象,本质是弥补编译期类型信息固定带来的局限;它通过class对象实现动态实例化、方法调用和成员访问,支撑spring等通用框架,但存在性能损耗、封装性削弱和api易错等问题。

面试时讲反射,别堆术语,重点说清它“为什么存在”和“解决什么问题”。一句话概括:反射是让Java程序在运行时能动态感知并操作类结构的能力,核心是Class对象,本质是弥补编译期类型信息固定带来的局限。
反射的核心概念:Class对象是唯一入口
每个类被JVM加载后,都会生成一个唯一的Class对象,它不是你写的类的实例,而是该类的“元数据镜像”——记录了类名、父类、接口、所有字段、方法、构造器、注解等完整结构。反射的所有操作(获取字段、调用方法、创建对象)都必须先拿到这个Class对象。它不是new出来的,是JVM在类加载阶段自动创建并维护的。
获取方式有三种,各有适用场景:
- 类名.class:最安全,编译期检查,适合已知类且无需异常处理
- 对象.getClass():适用于已有实例,常用于泛型擦除后的类型推断
- Class.forName("全限定名"):最灵活,支持运行时从配置、注解、网络传入的字符串加载类,但会触发类初始化,且需处理ClassNotFoundException
反射的核心作用:突破编译期限制,支撑通用框架
传统Java代码在编译时就必须确定类型(比如User user = new User()),而框架无法预知用户写的类。反射解决了这个根本矛盾:
- 动态实例化:Spring读取XML或注解中的类名,用Class.forName()加载,再通过Constructor.newInstance()创建Bean,不用硬编码new UserService()
- 动态方法调用:SpringMVC根据@RequestMapping路径匹配到Controller方法后,用Method.invoke()执行;MyBatis执行SQL后,用反射把ResultSet字段映射到实体类的私有属性上
- 动态访问成员:JUnit测试私有方法、Lombok生成的getter/setter底层依赖反射读写字段、Jackson序列化时跳过访问修饰符直接操作field.set()
回答时要带点分寸感:不能只夸优点
面试官想听你有没有工程意识。可以自然补一句:
- 它带来灵活性,但也付出代价:每次invoke或set都有安全检查、类型转换、栈帧开销,比直接调用慢5–10倍;
- 它绕过访问控制,可读私有字段、调用private方法,虽方便调试和框架实现,但也削弱封装性,部分Android环境或安全沙箱会禁用;
- 它的API易出错:getDeclaredMethod()和getMethod()区别、参数类型要精确匹配(int.class不能写Integer.class)、私有成员需先setAccessible(true),这些细节一错就抛异常。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











