这里不会介绍继承的基本概念和用法。这篇文章介绍继承中需要注意的几个点,并且文中也不会进行详细的理论说明,因为直接用示例,通过示例的结果进行总结分析,更清楚明了。
子类和父类的成员变量和构造方法的加载顺序
如果一个类继承了另一个类,在加载子类的构造方法时,会层次向上先加载父类的的构造。
另外需要注意的是,加载一个类的时候,类的成员变量会先于构造方法加载
class A {
private String s;
A(String s) {
this.s = s;
PrintUtils.print("Creating A: " + s);
}
protected void dispose() {
PrintUtils.print("disposing A: " + s);
}
}
class B {
private String s;
B(String s) {
this.s = s;
PrintUtils.print("Creating B: " + s);
}
protected void dispose() {
PrintUtils.print("disposing B: " + s);
}
}
class C {
private A a = new A("C-A");
private B b = new B("C-B");
C() {
PrintUtils.print("Creating C");
}
protected void dispose() {
PrintUtils.print("disposing C ");
a.dispose();
b.dispose();
}
}
class D extends C {
private A a = new A("D-A");
private B b = new B("D-B");
D() {
PrintUtils.print("Creating D");
}
protected void dispose() {
PrintUtils.print("disposing D ");
a.dispose();
b.dispose();
super.dispose();
}
}
class E extends D {
private A a = new A("E-A");
private B b = new B("E-B");
E() {
PrintUtils.print("Creating E" + " a是否为空: " + (a == null) + " B是否为空: " + (b == null));
}
protected void dispose() {
PrintUtils.print("disposing E ");
a.dispose();
b.dispose();
super.dispose();
}
}
public class PracticeDemo4 extends E {
private A a = new A("PracticeDemo4-A");
private B b = new B("PracticeDemo4-B");
public PracticeDemo4() {
PrintUtils.print("Creating PracticeDemo4");
}
protected void dispose() {
PrintUtils.print("disposing PracticeDemo4 ");
a.dispose();
b.dispose();
super.dispose();
}
public static void main(String[] args) {
PracticeDemo4 demo4 = new PracticeDemo4();
PrintUtils.print("Bye!");
demo4.dispose();
}
/**
*
*输出结果:
Creating A: C-A
Creating B: C-B
Creating C
Creating A: D-A
Creating B: D-B
Creating D
Creating A: E-A
Creating B: E-B
Creating E a是否为空: false B是否为空: false
Creating A: PracticeDemo4-A
Creating B: PracticeDemo4-B
Creating PracticeDemo4
Bye!
disposing PracticeDemo4
disposing A: PracticeDemo4-A
disposing B: PracticeDemo4-B
disposing E
disposing A: E-A
disposing B: E-B
disposing D
disposing A: D-A
disposing B: D-B
disposing C
disposing A: C-A
disposing B: C-B
*
*/
总结:
由打印结果会发现,先层层向上初始化父类的成员变量,父类的成员变量加载结束之后,加载父类的构造函数,最后才加载子类的成员变量和构造方法。
构造器内部的多态行为
class Parent4 {
public Parent4() {
PrintUtils.print("Parent4 before");
draw();
PrintUtils.print("Parent4 after");
}
public void draw() {
PrintUtils.print("Parent4 draw");
}
}
class Child4 extends Parent4 {
private int data;
public Child4(int r) {
data = r;
PrintUtils.print("Child4 data: " + data);
}
public void draw() {
PrintUtils.print("Child4 draw data: " + data);
}
}
public class PracticeTest5 {
public static void main(String[] args) {
new Child4(6);
PrintUtils.print("//////////////////////////");
new Child4(5);
PrintUtils.print("//////////////////////////");
new Child4(4);
PrintUtils.print("//////////////////////////");
new Child4(3);
PrintUtils.print("//////////////////////////");
new Child4(2);
PrintUtils.print("//////////////////////////");
new Child4(1);
PrintUtils.print("//////////////////////////");
/**
* 打印结果
*
* Parent4 before
* Child4 draw data: 0
* Parent4 after
* Child4 data: 6
* //////////////////////////
* Parent4 before
* Child4 draw data: 0
* Parent4 after
* Child4 data: 5
* //////////////////////////
* Parent4 before
* Child4 draw data: 0
* Parent4 after
* Child4 data: 4
* //////////////////////////
* Parent4 before
* Child4 draw data: 0
* Parent4 after
* Child4 data: 3
* //////////////////////////
* Parent4 before
* Child4 draw data: 0
* Parent4 after
* Child4 data: 2
* //////////////////////////
* Parent4 before
* Child4 draw data: 0
* Parent4 after
* Child4 data: 1
* //////////////////////////
*
*
*/
}
}
总结:
由结果可以看到,在创建子类的时候,执行了父类的构造方法。在父类中触发调用draw方法,由于被覆写了,所以调用的是子类的draw方法,但是此时子类的成员变量data还没有初始化,所以还是默认的初始值0,而不是我们设置的值。直到子类的初始化完成,在子类的构造中打印的结果data才是我们设置的值。
网友评论