Java 反射中字段获取的常见误区
在框架开发或者动态代理场景下,我们经常需要操作类的成员变量。这时候反射 API 里的 getFields() 和 getDeclaredFields() 就成了高频考点,很多人容易混淆,导致运行时出现意料之外的结果。
核心差异
这两个方法虽然名字很像,但行为逻辑完全不同:
- getFields():只返回当前类及其父类中所有**公开(public)**的字段。如果你继承了一个父类,父类的 public 字段也会出现在结果里。
- getDeclaredFields():返回当前类中所有声明的字段,不管访问修饰符是 public、private 还是 protected,但它不包含父类的字段。
类似的逻辑也适用于构造器和方法:getConstructors() 对应 getDeclaredConstructors(),getMethods() 对应 getDeclaredMethods()。
实战示例
直接看个例子。假设有一个父类 Base 和一个子类 Child:
class Base {
public String basePublic = "base";
private String basePrivate = "private";
}
class Child extends Base {
public String childPublic = "child";
private String childPrivate = "private";
}
当我们对 Child.class 调用反射时:
- 调用 getFields() 会拿到两个字段:basePublic 和 childPublic。注意,basePrivate 和 childPrivate 因为不是 public,所以被过滤掉了。
- 调用 getDeclaredFields() 则会拿到四个字段:basePublic, basePrivate, childPublic, childPrivate。但这里没有父类 Base 的其他非声明字段(如果有的话),且严格限制在当前类定义范围内。
什么时候用哪个?
日常工作中,选择哪种方式取决于你的目的:
- 如果你只是想通过公开接口访问对象属性,或者做通用的序列化逻辑,getFields() 更安全,因为它遵循封装原则。
- 如果你在做依赖注入、ORM 映射或者需要访问私有字段进行调试,getDeclaredFields() 是必须的。不过要注意,访问私有字段前通常需要调用 setAccessible(true) 来绕过 Java 的安全检查。
理解这两者的边界,能有效规避很多反射相关的 Bug,尤其是在处理复杂继承体系的时候。

