java子类引用父类对象_《Think in java》里这个例子中为什么父类引用能调用子类对象里的变量?...

首先看这个:

Super sup = new Sub();

这是sup变量包含两个方面:

它定义的类型是Super

它实际上引用了Sub的实例(对象)

定义的类型是给编译器在编译阶段参考的(用于编译时 Debug 和分配好成员变量的地址等);而实际的引用是在运行时通过调用真实引用的对象的方法实现多态的。

所以sup.field在编译时就确定为Super#field的地址,所以为0;

而sup.getField()在运行时调用Sub#getField(), 所以是得到Sub#field的1.

PS. 你在读这本书时,通常不能指望一次读懂。能看懂多少就看多少,看多几次。不过有个很好的官方教程 The Java Tutorials, 这个教程我觉得是学 Java 最好的资料,就看你习不习惯读英文。

再看一个更加能够说明问题的例子Demo:

class Dad {

public int field = 6666;

public int getField() {

return field;

}

}

class Son extends Dad {

public int field = 9999;

public int getField() {

return field;

}

}

public class Main {

public static void main(String[] args) {

Dad dd = new Dad();

Dad ds = new Son();

Son ss = new Son();

// java.lang.ClassCastException: Dad cannot be cast to Son

// Son sd = (Son) new Dad();

// 如果直接访问成员变量(field),

// 它的值由对象引用(dd, ds, ss)的类型决定,

// 而且它的地址在编译期间就已经分配

System.out.println("Dad new Dad(): " + dd.field); // 6666

System.out.println("Dad new Son(): " + ds.field); // 6666

System.out.println("Son new Son(): " + ss.field); // 9999

// 但是如果通过方法间接访问,

// 那么它得到的值由真实的对象决定,与其定义的类型无关

// 而且这是在运行时才能决定的

System.out.println("Dad new Dad(): " + dd.getField()); // 6666

System.out.println("Dad new Son(): " + ds.getField()); // 9999

System.out.println("Son new Son(): " + ss.getField()); // 9999

// 这种不一致性并不是不能避免,反而是为了提高效率而有意为之的

// 继续放大招... 注意同一个对象转型前后发生的变化

// 转型前:9999 转型后:6666

System.out.println("转型前:" + ss.field + " 转型后:" + ((Dad) ss).field);

// 转型前:6666 转型后:9999

System.out.println("转型前:" + ds.field + " 转型后:" + ((Son) ds).field);

System.out.println(ss.field == ((Dad) ss).field); // false

System.out.println(ds.field == ((Son) ds).field); // false

// 这说明了,不要直接访问成员变量!!!!

// 还有一些重要的问题,你慢慢再掌握,:))

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值