编程后端开发工程师

在Java中,反射(Reflection)是什么?它的优点、缺点和潜在风险是什么?

用 Hintsage AI 助手通过面试

答案

反射是一种机制,允许在程序运行时检查和修改类、对象、方法和字段的结构和行为。它通过java.lang.reflect包实现。

它允许:

  • 在运行时获取有关类的信息
  • 动态调用方法和访问字段
  • 根据名称创建类的新实例

示例:

import java.lang.reflect.Method; public class ReflectionExample { public void greet() { System.out.println("Hello!"); } public static void main(String[] args) throws Exception { Class<?> clazz = Class.forName("ReflectionExample"); Object instance = clazz.getDeclaredConstructor().newInstance(); Method method = clazz.getMethod("greet"); method.invoke(instance); // 输出:Hello! } }

优点:

  • 灵活性和可扩展性(例如,框架,DI)
  • 能够在不知道对象类型的情况下进行通用代码操作

缺点/风险:

  • 性能下降
  • 潜在的安全问题(绕过访问修饰符)
  • 破坏封装性
  • 支持性较差

反向问题

是否可以通过反射访问类的private字段和方法,以及后果是什么?

答案: 是的,可以通过FieldMethodsetAccessible(true)方法实现:

Field field = clazz.getDeclaredField("privateField"); field.setAccessible(true); field.set(obj, "value");

这会破坏类的封装性,并带来风险:情况变得脆弱,可能出现安全错误,而在新版本的JVM中此类操作可能会受到访问策略的限制。

由于对主题细微差别缺乏了解而导致的实际错误示例


故事

在一个大型项目中,通过反射自动映射DTO时,类型为"Optional"的字段未被正确考虑,这导致在批量处理数据时出现NullPointerException,因为反射包不区分Optional值和null。


故事

在银行软件中,通过setAccessible(true)访问私有字段以进行序列化。在JVM更新后,行为发生了变化,访问私有字段变得被禁止,重要的序列化功能在生产中突然停止工作。


故事

在ORM框架中,在生成代理对象时忘记在数据模式更改后刷新反射缓存。结果,系统在处理新类字段时产生不可预测的异常,而这些字段未反映在缓存中。