Java中字段访问不体现多态性,严格依据变量的编译时类型决定;子类同名字段是隐藏而非重写,强制转型会改变字段访问目标,应避免字段隐藏而用getter/setter实现多态。

Java 中多态下字段访问不体现多态性,而是严格依据变量的编译时类型(即声明类型)来决定访问哪个字段。这是与方法调用最根本的区别:方法看运行时类型(动态绑定),字段看编译时类型(静态绑定)。
字段访问是静态绑定,与继承无关
即使子类中定义了同名字段,也**不是重写(override)**,而是**隐藏(hiding)**。JVM 在编译阶段就根据引用变量的声明类型确定访问哪个字段,不会等到运行时去查对象实际类型。
例如:
class Parent { int x = 10; }
class Child extends Parent { int x = 20; }
Parent p = new Child();
System.out.println(p.x); // 输出 10,不是 20
这里 p 的编译时类型是 Parent,所以访问的是 Parent 类中的 x 字段,哪怕实际对象是 Child 实例。
强制转型后字段访问随之改变
一旦通过显式类型转换改变引用的编译时类型,字段访问目标也会立即变化,因为绑定发生在编译期,而转型会生成新的编译时视图。
继续上面的例子:
Child c = (Child) p; System.out.println(c.x); // 输出 20
此时 c 的编译时类型是 Child,所以访问 Child 类中定义的 x 字段。注意:这和方法调用不同——方法不需要转型也能多态执行子类版本。
字段多态的“假象”常源于误解
初学者有时观察到“字段像有多态”,往往是因为以下情况:
- 误把 getter 方法当成了字段访问(getX() 是方法,遵循多态;x 是字段,不遵循)
- 子类未定义同名字段,导致访问的仍是父类字段(看似“一致”,实则无多态)
- 使用了 IDE 自动补全或调试器显示,混淆了变量声明类型与实际对象类型
设计建议:避免字段隐藏,优先使用 getter/setter
为消除歧义、保证行为可预测,应:
- 将字段设为 private,不提供同名 public/protected 字段
- 通过 protected 或 public 的 getter 方法暴露值,并在子类中重写该方法实现逻辑多态
- 若需不同字段语义,考虑组合或新字段命名,而非同名隐藏
这样既符合封装原则,又让多态行为清晰可控。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











