做这道题,首先要明白类加载时执行顺序::
new 子类对象时的执行顺序:Ø 当new子类对象, 的执行顺序(省去了加载) Ø 所有属性 (父类和子类) 都赋值为默认值; Ø 父类的构造代码块和父类的显示初始化语句; Ø 父类构造器的代码; Ø 子类的构造代码块和子类的显示初始化语句; Ø 子类的构造器代码.
有了上面的说明, 我们再来看代码:
class FatherClass {
int field = 0; FatherClass() {
field++;
} public void show() {
System.out.println(field);
}
}class ChildClass extends FatherClass {
{
field = 10;
} ChildClass() {
super();
field = super.field;
} public void show() {
System.out.println(field);
}
}class Demo {
public static void main(String[] args) {
//这里是用的是多态,创建的是一个子类对象, 即父类的引用指向子类对象, 那么既然对象是子类, 我们就结合我上面面说的, 当new 子类对象是, 程序做了些什么?
1, 首先就是Field属性, 默认初始化值,那么Filed的值就是0, 至于这里为什么要这样执行, 首先在new子类对象时, 因为子类对象总会隐式调用父类的无参构造器,你这里的代码没有隐式调用,自己写出来了, 是显示调用, 但是不管是显示,还是隐式,都会调用, 那么当调用父类的构造器的时候, 那么就要对父类进行初始化, 所以,这也是为什么要说每个子类都有一个父类对象的原因
2,执行父类构造代码块和父类显示初始化语句, 这里因为没有构造代码块, 那么就没有执行,仅仅执行了显示初始化语句, 也就是 int Field = 0;第二步执行完成;
3,执行父类构造器的代码,Filed++, 那么这个时候Filed的值是1;
4, 父类初始化动作完成, 接着执行子类的构造代码块, Filed = 10. 这个时候Filed的值就是10了, 这里要注意,在执行这句代码的时候Field的值已经是10了, 因为继承的关系,每个子类都有一个父类对象,先是父类执行初始化,然后是子类, 但是它们的属性用的都是同一个, 所以当子类做初始化动作的时候, 属性值被改变, 那么父类的属性值也跟着改变了,, 所以在做完这个动作后, 不论是父类还是子类的Field的值都是10, 其实本来就只有一个Filed, 只是父类先Fild++, Filed变为1, 然后子类再 Filed = 10, Filed的值为10
5,执行子类构造器的代码 Filed = super.Filed, 既然这样,Filed的值当然是10了, 因为super.Filed的值就是父类的值, 而父类的值因为子类的重新赋值而变成了10
FatherClass f = new ChildClass();
//这个简单了,多态调用, 多态调用只需知道, 能不能调用看左边, 具体调用那个看右边,(不过注意属性和静态方法不包括在此列,他们调用只看属性), 具体解释下, 左边引用f是FatherClass类,那么这个类到底有没有show()方法了, 有,能调用, 没有肯定就会出错, 事实上我们的代码在FatherClass类中是有show()方法,那么就说明f引用能够调用show方法,接下来具体调用哪一个show()方法呢? 具体调用看右边, 因为右边是子类对象, 那么调用的方法就是子类的show()方法, 所以最后打印结果为10
f.show();
//这个执行过程和上面的完全一样,所以结果也是一样 , 最后打印结果为10
ChildClass c = new ChildClass();
c.show();
}
} |