反射操作List元素的核心是对泛型元素对象的属性读写,分调用getter/setter方法(符合封装但性能低)和直接字段访问(性能高但绕过逻辑、有安全风险)两种方式,实际应用推荐缓存Method/Field并混合使用。

反射操作 List 元素时,核心不是“对 List 本身反射”,而是对 List 中的**泛型元素对象**进行属性读写。关键区别在于:是通过反射调用其 getter/setter 方法,还是绕过方法、直接访问私有字段(配合 setAccessible(true))。两者在语义、安全性、性能和可维护性上差异明显。
调用 get/set 方法:符合封装,但开销略高
这种方式严格遵循 Java Bean 规范,通过 getMethod("getXXX") 和 invoke() 执行逻辑,能触发属性校验、日志、监听等业务逻辑(如果存在)。适合需要保留原有行为的场景,比如框架做 DTO 转换或审计增强。
- 必须确保目标类存在标准命名的 public 方法,否则会抛
NoSuchMethodException - 每次调用都要解析方法签名、检查访问权限、执行栈帧压入,比直接字段访问慢约 3–5 倍(实测千万次级调用差距在百毫秒量级)
- 无需
setAccessible,不受模块系统(Java 9+)或安全管理器限制
直接 Field 访问:快且直接,但绕过封装
使用 getDeclaredField("xxx") + setAccessible(true) + set()/get(),跳过方法调用,直抵内存字段。性能接近原生赋值,适合高性能映射(如 JSON 反序列化库内部)。
- 可访问 private/protected/default 字段,但需显式设为可访问;Java 12+ 在强封装模式下可能抛
InaccessibleObjectException - 完全跳过 setter/getter 中的任何逻辑(如空值检查、格式转换、事件通知),可能引发隐性 bug
- 字段名硬编码,重构时易断裂;建议配合
Field缓存(如用ConcurrentHashMap<class map field>></class>)避免重复查找
实际 List 场景中的典型写法
假设 List<person></person>,要批量设置每个 Person 的 name 属性:
- 方法调用方式:
Method setName = Person.class.getMethod("setName", String.class); for (Person p : list) setName.invoke(p, "newName"); - 字段直写方式:
Field nameField = Person.class.getDeclaredField("name"); nameField.setAccessible(true); for (Person p : list) nameField.set(p, "newName"); - 混合策略更实用:首次缓存
Method或Field实例,后续复用;对无 setter 的字段自动降级为 field 访问
安全与兼容性提醒
在模块化环境(如 JDK 9+ 的 module-info.java)中,直接访问非导出包内的私有字段会失败。此时要么开放模块导出,要么改用方法调用。生产环境若启用安全管理器,setAccessible(true) 还需授予 ReflectPermission("suppressAccessChecks") 权限。

















