Child继承Parent并声明同名字段label,很多人以为这也是"覆盖"——这篇真实用Parent p = new Child()构造出引用类型和运行时类型不一致的场景,对比字段访问和方法调用的真实差异。
上一篇:多维数组内存真实验证
Parent和Child各自声明同名的static字段label和实例字段instanceLabel,用Parent p = new Child()这种"父类引用指向子类对象"的经典场景来测试。
StaticFieldHidingDemo.java static class Parent { static String label = "Parent-static"; String instanceLabel = "Parent-instance"; } static class Child extends Parent { static String label = "Child-static"; String instanceLabel = "Child-instance"; } Parent p = new Child();
真实p.label(引用类型是Parent) 结果: Parent-static 真实Child.label 结果: Child-static 真实Parent.label 结果: Parent-static 真实p.instanceLabel(引用类型是Parent) 结果: Parent-instance 真实c.instanceLabel(引用类型是Child) 结果: Child-instance 真实((Child)p).instanceLabel 结果: Child-instance
真实结果证明:不管是static字段还是普通实例字段,p.label和p.instanceLabel真实都返回了Parent版本的值,尽管p运行时指向的真实是一个Child对象。这是因为字段访问在编译期就真实按变量的声明类型(Parent p)静态绑定了要访问哪个字段,和这个引用运行时实际指向什么对象完全无关。真实测试还验证了强制转型((Child)p).instanceLabel后立刻切换回Child版本——因为转型改变了编译器用来做字段绑定的静态类型。
StaticFieldHidingDemo.java static class Child extends Parent { @Override String describe() { return "Child-method"; } // 真实覆盖 } p.describe(); // p的引用类型仍是Parent
真实p.describe()(引用类型Parent,实际对象Child) 结果: Child-method
每一行都是真实运行这段代码得到的结果。