问题:
tij中的习题:
class BaseWithPrint {
public BaseWithPrint() {
p.println("BaseWithPrint()");
print();
}
public void print() {
System.out.println("BaseWithPrint.print");
}
}
class DerivedWithPrint extends BaseWithPrint {
int i = 47;
public DerivedWithPrint() {
p.println("DerivedWithPrint()");
}
public void print() {
System.out.println("i = " + i);
}
}
public class GetFile {
public static void main( String args[] ){
DerivedWithPrint dp = new DerivedWithPrint();
dp.print();
}
}
输出结果如下:
在父类构造函数BaseWithPrint()中调用print(),既然是在父类的构造函数里,那么子类自然还没有构造,其成员函数按说也应该是不存在的呀!可是为什么这时可以调用子类的print()呢?
回答:
一、运行时刻
a +----+ -+---+-
| |
| | A
| |
b +----+ -+- C
| |
| | B
| |
c +----+ -+---+-
我先用这个图表示类及其子类在
内存
中的逻辑概念上的分布。
其中:
1) 图形中的方框表示类在内存中的存储范围。
2) A表示从a点到b点的内存区
3) B表示从b点到c点的内存区
4) C表示从a点到c点的内存区
现在有一个类SuperClass及其子类SubClass被加载到内存。其中SuperClass加载于内存区A,那么SubClass占用哪一部分内存呢?
正确答案是C而不是B。
二,从代码角度观察
对于继承,我们首先应该这样理解,代码中使用继承,只是为了减少代码量(那位,先把砖头放下),而不管父类还是子类,都是相对独立的类。
当一
个子
类继承自其父类时,从代码角度,就是把其父类的代码重写一遍,然后再加上额外的代码,从而,成其子类。其实,这一
工作
是编译器完成的,当然也不是重写代码,但是我们可以这么直观的理解。
我按照这种思路改造你的DerivedWithPrint,得到下面的代码:
// 注意,去掉了extends
class DerivedWithPrint {
int i = 47;
public DerivedWithPrint() {
//来自BaseWithPrint
p.println("BaseWithPrint()");
print();
// 本地
p.println("DerivedWithPrint()");
}
public void print() {
System.out.println("i = " + i);
}
}
这就是DerivedWithPrint类在运行时刻应该执行的命令及顺序。因为原来的DerivedWithPrint中也有print方法,所以覆盖了其父类的print方法。上述过程好像叫做类的扁平化。
注意,如果原DerivedWithPrint的print方法中有super.print()字样,那么扁平化之后的print方法应该这样:
public void print() {
System.out.println("BaseWithPrint.print");
System.out.println("i = " + i);
}