向上造型中让我入坑的地方 (><)

    今天周六,闲着蛋疼就报名参加了公司的一个java比赛,比赛地点某某大厦11楼会议室,想象中应该是能容纳上百人的超大会议室。没成想,到地方一看,只是一个
能容纳六七人的有圆形会议桌的小会议室。不过这仍然不能熄灭BZ因对Java热爱而燃起的满腔激情,于是满怀热情地投入到了比赛答题中。
一般这样的开头都会给人一种欲抑先扬的感觉,BZ这次当然也不例外...刚开始没做几题,就被其中的一个小题目给绊倒了,题目大体是这样的:
有两个类,一个叫BaseHole,如下所示:
public class BaseHole {
public int i = 1;
public BaseHole () {
bh();
}
public void bh () {
System.out.println("Base Hole - bh()");
}
}
另一个类继承了上面的BaseHole,如下所示:
public class UpConstrutorHole extends BaseHole{
public int i = 2;
public void bh () {
System.out.println("UpConstrutorHole - bh()");
}
public void uch () {
System.out.println("UpConstrutorHole - uch()");
}
}
然后运行如下代码:
public class UpConstructorClient {
public static void main(String[] args) {
BaseHole b = new UpConstrutorHole();// 第8行
System.out.println(b.i);// 第9行
        UpConstrutorHole u = (UpConstrutorHole) b;
        u.uch();// 第11行
u.bh();// 第12行
}
}
问8/9/11/12各行代码分别输出的结果是什么:
A.Base Hole - bh()
1
UpConstrutorHole - uch()
UpConstrutorHole - bh()
B.由于向上造型后b中没有uch()方法,所以第10行给b强转类型后仍然没有uch()方法,故第11行编译报错无法执行
C.Base Hole - bh()
2
UpConstrutorHole - uch()
UpConstrutorHole - bh()
D.UpConstrutorHole - bh()
2
UpConstrutorHole - uch()
UpConstrutorHole - bh()
E.UpConstrutorHole - bh()
1
UpConstrutorHole - uch()
UpConstrutorHole - bh()
本着诚实守信的原则,通过分析上题看看自己是否真正的深刻了解向上造型,务必要先在心里想好自己的答案再往下看。

对于向上造型,我之前知道的点基本就是以下两点:
1、向上造型后的对象,能引用的方法为:如果子类的方法满足重写父类方法的要求,则引用子类的方法,否则引的是父类的方法,毕竟对象的类型是父类类型;
2、向上造型,子类的属性不能覆盖父类。
通过以上两点,可知第9行是1,第12行是UpConstrutorHole - bh(),排除CD,还剩ABE,下面才是本题的重难点。
剩余的ABE总共涉及到两部分内容:
第一部分是B中的强制类型转换,同一个引用,为什么前者没有uch方法,而类型转换之后就有了呢?(所以B是不对的,仿佛是

在用貌似合理的话胡说八道,但是如果强制类型转换原理了解不清楚,很容易就被忽悠了,BZ就是很悲催的踩入了坑里 -- FK) 首先第8行那里进行向上造型,
new了一个UpConstrutorHole对象,就是说在堆内存中真真切切的生成了一个UpConstrutorHole对象,对象的实体数据中存放的就是这个类中的代码,这一点是
确定无疑的;其次,为什么把UpConstrutorHole对象赋值给b引用后就访问不到uch了呢?其实就是BaseHole类型的引用是有可见范围的,该可见范围
包括b中已有的方法属性跟被UpConstrutorHole类重写的方法,而UpConstrutorHole中的其余方法对该引用不可见,所以形成了向上造型的这种访问形式;
第三,为什么强制类型转换后就又能访问uch方法了呢?还是这个引用指针捣的鬼,强制类型转换后,引用的可见范围被改变,变为可以访问到UpConstrutorHole
类中的方法,所以又能引用到uch方法,虽然对象没变,引用地址没变,但是只要引用的类型变了其访问范围也会改变。至此,B的迷雾已经被拨开,pass掉。
第二部分,运行程序可知第8行输出的是UpConstrutorHole类中的bh方法打印的字符,为什么父类的构造器中执行的也是子类中重写的方法呢?其实这就要
追溯到对象初始化的时候的执行顺序了,翻阅了一下"圣经" - 《Thinking In Java》,发现有相关讲解,大意如下:
构造器初始化的顺序:
1、先将分配给对象的存储空间初始化为二进制的0;
2、在子类构造器执行前,先调用基类的构造器,此时如果基类的构造器中有子类重写的方法,会调用子类中的方法;
3、按顺序调用成员变量的初始化方法;
4、调用子类的构造器
而且后面还特意加了一句嘱咐:编写构造器时,尽可能的避免调用其他方法,尤其是非final跟private的方法。不然就可能出现如上题所示的莫名现象。
经此一役,发觉要学的东西仍然浩如烟海。还是那句话,学习之路,一定要多给自己灌鸡汤,Never at rest!





posted on 2018-12-15 20:59  淡墨痕  阅读(468)  评论(0编辑  收藏  举报