Java中字段访问不具多态性,仅按引用声明类型静态绑定;方法调用才基于实际对象类型动态绑定。字段是状态,归属声明类型;方法是行为,归属实际类型。需多态语义时应封装为getter方法。

Java 中继承关系下,多态调用时属性(字段)不体现多态性,本质是语言设计上的明确选择:字段访问走编译期静态绑定,而方法调用才走运行期动态绑定。
字段访问只看引用声明类型,不看实际对象类型
编译器在编译阶段就根据变量的**声明类型**确定要访问哪个字段。即使该变量实际指向子类对象,只要声明是父类类型,访问的就是父类中定义的字段。
-
例如:
Parent p = new Child(); p.field;访问的是Parent.field,不是Child.field - 子类中同名字段不是“覆盖”,而是“遮蔽(shadowing)”——它和父类字段各自独立存在,内存地址不同、互不影响
字段没有动态分派机制,JVM 不查虚方法表
方法支持多态,是因为 JVM 在运行时通过虚方法表(vtable)查找实际类型对应的方法入口;而字段没有 vtable,JVM 直接按引用类型计算字段在内存中的偏移量,跳过运行时类型判断。
- 子类字段与父类字段是两个完全不同的变量,哪怕名字、类型都一样
- 不存在“字段重写”的概念,只有“字段隐藏”
语言规范刻意区分状态与行为的语义
Java 明确将字段视为“状态”,归属由声明类型决定;方法视为“行为”,实现由实际类型决定。这种分离保障了字段访问的可预测性和调试确定性。
- 如果字段也支持多态,同一行
p.field的含义会随运行时对象类型变化,容易引发歧义和 bug - 需要多态语义的“值”,应封装为 getter 方法:
p.getValue()—— 它天然支持动态绑定
代码示例一眼看清差异
以下输出结果是 40 / 40 / 18 / 18 / 18 / 40,清楚说明字段不具多态性:
Father a = new Father(); // a.age → 40 Children b = new Children(); // b.age → 18 Father c = new Children(); // c.age → 40(声明类型是 Father) a.getAge(); // 输出 40(this.age 是 Father.age) b.getAge(); // 输出 18(this.age 是 Children.age) c.getAge(); // 输出 18(c 实际是 Children,this 指向子类实例)
注意:最后一行 c.getAge() 输出 18,是因为 getAge() 是重写方法,this.age 中的 this 是运行时对象,所以取的是子类字段——这正说明:**字段本身不具多态性,但方法内的 this.字段 能体现多态,靠的是 this 的运行时类型,而非字段本身的绑定机制**。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











