java反射获取类结构的核心是class对象,三种获取方式为:类名.class(编译期已知、安全高效)、对象.getclass()(已有实例、无异常)、class.forname("全限定名")(动态加载、抛classnotfoundexception)。

面试官考 Java 反射获取类结构,核心是看你能不能把“类在运行时是什么样子”这件事说清楚、操作对、理解深。不是背 API,而是看你会不会用反射这面“镜子”,照出类的骨架和细节。
考 Class 对象怎么来
这是起点,必须答准三种方式及其适用场景:
- 类名.class:编译期已知类,最安全高效,比如框架中硬编码类型时
- 对象.getClass():运行时已有实例,适合通用工具方法(如通用打印对象字段)
- Class.forName("全限定名"):靠字符串动态加载,常用于配置驱动类(如 JDBC 的 Class.forName("com.mysql.cj.jdbc.Driver"))或插件机制
如果只答一种,或者混淆 forName 和 getClass 的异常差异(前者抛 ClassNotFoundException,后者不会),基本就露底了。
考字段、方法、构造器怎么列
重点区分 public 和全部(含 private)的获取方式,以及是否需要打破封装:
- 获取所有字段:getDeclaredFields()(含 private),但要调用 setAccessible(true) 才能读写
- 获取公共字段:getFields()(只返回 public 且可被继承的)
- 获取所有方法:getDeclaredMethods();获取公共方法:getMethods()(含父类 public 方法)
- 获取构造器同理:getDeclaredConstructors() vs getConstructors()
面试官常追问:“getMethods() 返回的方法里,为什么有 Object 的 toString() 却没有 private 方法?”——答案是它只返回本类及父类的 public 实例方法,不包含 private 或 static 方法。
考怎么安全地操作私有成员
不能只说“加 setAccessible(true)”,得讲清边界和风险:
- setAccessible(true) 是绕过 JVM 访问检查,但仅对当前 Field/Method/Constructor 生效
- Java 9+ 模块系统下,如果类在非开放模块中,可能抛 InaccessibleObjectException,需配合 --add-opens 参数
- 修改 final 字段理论上可行,但若该字段是编译期常量(如 static final String = "abc"),JVM 已内联,改了也看不到效果
有人现场手写代码漏掉 setAccessible(true),或者用 getFields() 去取 private 字段导致空指针,就是典型失分点。
考反射的实际用途和代价
面试官想确认你不是纸上谈兵:
- 典型用途:Spring 的 IOC 容器创建 Bean、MyBatis 封装 ResultSet 到实体类、JUnit 运行 @Test 方法、Lombok 编译期生成代码的验证逻辑
- 性能代价:反射调用比直接调用慢 5–10 倍(尤其首次),因为要解析符号引用、做访问校验、取消内联优化
- 替代思路:高频调用场景可用 MethodHandle 或 VarHandle(Java 9+)提升性能;简单映射可用字节码增强(如 ByteBuddy)或编译期注解处理器
如果只说“反射很慢所以少用”,没提具体慢在哪、怎么优化、为什么框架又离不开它,说明理解浮于表面。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











