问题
Java 中父类的方法可以被子类重写,但属性不能重写,即使子类中定义了完全一样的属性。那如果父子出现相同属性时,会出现什么情况呢?
答案是:变量在声明时是什么类型,读取的就是该类型的中的属性值。如下虽然 p 与 c 指向同一个对象,但输出的是 Parent 中 str 的值
Child c = new Child();
Parent p = (Parent) c;
System.out.println(p.str);
我们可以看一下 p.str 对应的字节码,可以发现它指向的是 Parent.str
getfield #52 // Field com/example/test/Parent.str:Ljava/lang/String;
再看一下 c 的内存结构,可以发现该对象的内存中有两个 str 变量,一个是 Parent.str,一个是 Child.str。所以通过上面字节码访问到的一定是 Parent.str,它与 Child.str 是完全不同的两块内存
12 4 java.lang.String Parent.str (object)
...
20 4 java.lang.String Child.str (object)
与泛型的结合
泛型存在类型擦除,会被替换成最小的上界,比如下面代码在实际编译成的字节码中 T 会被替换成 Parent,因此无论我们在构造 TestG 时传入的是哪个实例,输出的永远都是 Parent.str。结论是:由于存在泛型擦除,所以访问的都是擦除后的类属性,而不管传入的实际类型是啥
public class TestG<T extends Parent> {
private T t;
public TestG(T t) {
this.t = t;
}
public void print() {
System.out.println(t.str);
}
}
Debug
父子同名属性在 Debug 中看不出来任何问题,只有真正运行时才会发现不对。