java 子类声明与父类同名字段时,并非覆盖,而是**字段隐藏(field hiding)**:子类对象在内存中实际包含两份独立的 `x` 字段(`parent.x` 和 `child.x`),分别由各自构造器初始化,通过 `this.x` 和 `super.x` 可明确访问不同副本。
在 Java 中,当子类 C 继承父类 P 并定义了同名字段(如 int x;),这并非“重写”或“覆盖”,而是一种明确的语言特性——字段隐藏(Field Hiding),由《Java 语言规范》(JLS §8.3)明确定义:子类中同名字段会隐藏所有可访问的父类同名字段。关键在于:隐藏 ≠ 合并,它导致同一个对象实例中物理存在两个独立的 x 字段,分别隶属于父类和子类的继承层级。
虽然 new C() 只创建一个对象实例,但该实例的内存布局包含:
二者在内存中是完全独立的变量,占据不同偏移地址,互不干扰。
你观察到的输出:
c.x: 2 c.getX(): 1
正是字段隐藏行为的直接体现:
✅ 正确访问双字段的示例:
class Child extends Parent {
int x;
Child() {
super(); // 显式调用父构造器(可省略,但强调执行顺序)
this.x = 2; // 初始化 C
hild.x
}
void printBothXs() {
System.out.println("this.x (Child.x): " + this.x); // 输出 2
System.out.println("super.x (Parent.x): " + super.x); // 输出 1
}
}总结来说,Java 的字段隐藏机制让单个对象能安全容纳多份同名字段,提升继承灵活性,但也要求开发者清晰区分 this. 与 super. 的语义边界——这不是 bug,而是 JLS 精心设计的、可预测的语言特性。