Java中 Class.getDeclaredField 怎么获取类中直接声明的 private 字段

作者:袖梨 2026-07-21
Class.getDeclaredField()仅获取当前类直接声明的字段(不含父类),包括private字段,但需调用setAccessible(true)才能访问;字段名严格区分大小写,不支持继承查找,不存在时抛NoSuchFieldException。

Class.getDeclaredField 可以获取当前类**直接声明**(不包括父类)的任意访问权限字段,包括 private 字段。关键在于它只查本类,且不检查访问控制——但默认不能直接读写,需配合 setAccessible(true)

只获取本类声明的 private 字段(不继承)

getDeclaredField(String name) 不会向上查找父类或接口中的字段,哪怕父类有同名 private 字段,也只会返回当前类中定义的那个(如果存在)。若字段不存在,抛出 NoSuchFieldException

  • 子类无法通过该方法获取父类的 private 字段(即使同名)
  • 接口中不允许有 private 字段(Java 9+ 接口可有 private 方法,但字段仍是 public static final
  • 匿名内部类、Lambda 表达式生成的类也可用,但字段名需按编译器生成的实际名称(如 val$x

必须调用 setAccessible(true) 才能访问 private 字段

获取到 Field 对象后,它的 get() / set() 默认受 Java 访问控制限制。对 private 字段操作前,必须显式绕过检查:

Field field = clazz.getDeclaredField("secret");field.setAccessible(true); // 关键一步Object value = field.get(instance);field.set(instance, newValue);
  • 跳过 JVM 的访问检查,不是“破坏封装”,而是反射的合法能力
  • 在启用 SecurityManager 的环境中可能被拒绝(现代应用极少启用)
  • setAccessible(true) 对同一个 Field 实例只需调一次,后续操作无需重复

注意字段名必须完全匹配(区分大小写)

Java 字段名严格区分大小写,且不含任何修饰符信息。例如:

立即学习“Java免费学习笔记(深入)”;

  • 类中有 private String userName; → 必须传 "userName",不能是 "username""USERNAME"
  • IDE 自动生成的字段(如 Lombok 的 @Data)字段名就是代码里写的名称,不是 getter/setter 名
  • 编译器生成的合成字段(如枚举的 $VALUES)也可通过此方法获取,但名字需查字节码确认

替代方案:getDeclaredFields() 遍历所有声明字段

如果不知道字段名,或需要批量处理本类所有 private 字段,可用:

Field[] fields = clazz.getDeclaredFields();for (Field f : fields) {    if (Modifier.isPrivate(f.getModifiers())) {        f.setAccessible(true);        // 处理 f    }}
  • getDeclaredFields() 返回全部字段(public/protected/private/default),不含继承字段
  • Modifier.isPrivate(int) 判断访问修饰符
  • 适合通用工具类(如深拷贝、序列化框架)中自动处理私有成员

相关文章

精彩推荐