Java语言基础:对象的初始化
2011年03月29日 19:49 发布者:1770309616
345681. 如果基类存在默认构造函数,则在子类构造之前,会先调用基类的默认构造函数:
view plaincopy to clipboardprint?
01.class A {
02. A() {
03. System.out.println("A create");
04. }
05.}
06.
07.class B extends A {
08. B() {
09. // 会在这里先调用A的默认构造函数
10. System.out.println("B create");
11. }
12.}
13.
14.class C extends A {
15. C(int i) {
16. // 会在这里先调用A的默认构造函数
17. System.out.println("C create");
18. }
19.}
20.
21.public class Main {
22. public static void main(String[] args) {
23. B b = new B();
24. C c = new C(10);
25. } 26.}
27.
28.// 输出为:
29.A create
30.B create 3
1.A create
32.C create
class A {
A() {
System.out.println("A create");
}
}
class B extends A {
B() {
// 会在这里先调用A的默认构造函数
System.out.println("B create");
}
}
class C extends A {
C(int i) {
// 会在这里先调用A的默认构造函数
System.out.println("C create");
}
}
public class Main {
public static void main(String[] args) {
B b = new B();
C c = new C(10);
}
}
// 输出为:
A create
B create
A create
C create
2. 如果基类只有带参数的构造函数,子类必须在自己的构造函数中通过super(...)显式调用该基类构造函数:
view plaincopy to clipboardprint?
01.class A {
02. A(int i) {
03. System.out.println("A create");
04. }
05.}
06.
07.class B extends A {
08. B() {
09. // 必须在这里显式调用父类的非默认构造函数,否则编译不通过
10. // 注意这调用只能放在最前面,否则编译不通过
11. super(20);
12. System.out.println("B create");
13. }
14.}
15.
16.class C extends A {
17. C(int i) {
18. // 必须在这里显式调用父类的非默认构造函数,否则编译不通过
19. // 注意这调用只能放在最前面,否则编译不通过
20. super(30);
21. System.out.println("C create");
22. }
23.}
24.
25.public class Main {
26. public static void main(String[] args) {
27. B b = new B();
28. C c = new C(10);
29. }
30.}
31.// 输出为:
32.A create
33.B create
34.A create
35.C create
class A {
A(int i) {
System.out.println("A create");
}
}
class B extends A {
B() {
// 必须在这里显式调用父类的非默认构造函数,否则编译不通过
// 注意这调用只能放在最前面,否则编译不通过
super(20);
System.out.println("B create");
}
}
class C extends A {
C(int i) {
// 必须在这里显式调用父类的非默认构造函数,否则编译不通过
// 注意这调用只能放在最前面,否则编译不通过
super(30);
System.out.println("C create");
}
}
public class Main {
public static void main(String[] args) {
B b = new B();
C c = new C(10);
}
}
// 输出为:
A create
B create
A create
C create
3. 以上只讲了最简单的构造函数调用顺序,其实一个对象的真正的初始化过程应该是:
1.将对象的存储空间初始化为二进制的0.
2.先递归到最上层的基类去,将最上层的基类作为当前类。
3.对于当前类:
1.按声明顺序调用成员变量的初始设置代码。
2.调用构造函数。
4.接着将下一层继承类作为当前类,继续步骤3
先看下面的代码:
view plaincopy to clipboardprint?
01.class A {
02. A() {
03. System.out.println("A create");
04. }
05.}
06.
07.class D {
08. D() {
09. System.out.println("D create");
10. }
11.}
12.
13.class B extends A {
14. private D d = new D();
15. B() {
16. System.out.println("B create");
17. }
18.}
19.
20.class C extends B {
21. C(int i) {
22. System.out.println("C create");
23. }
24.}
25.
26.public class Main {
27. public static void main(String[] args) {
28. C c = new C(10);
29. }
30.}
class A {
A() {
System.out.println("A create");
}
}
class D {
D() {
System.out.println("D create");
}
}
class B extends A {
private D d = new D();
B() {
System.out.println("B create");
}
}
class C extends B {
C(int i) {
System.out.println("C create");
}
}
public class Main {
public static void main(String[] args) {
C c = new C(10);
}
}
初始化过程大概是这样的:
1. 先从C递归到B,再从B递归到A。
2.A没有成员变量,所以A的构造函数被调用。
3.接到回到B,B有一个D类的成员有初始化,因此D的构造函数被调用。
4.接着B的构造函数被调用。
5.最后回到C,C的构造函数被调用。
所以输出应该是:
A create
D create
B create
C create
4. 必须小心在构造函数中调用虚函数(在JAVA里普通函数都是虚的)的隐患,特别是在基类的构造函数,因为此时继承类的成员可能还没有初始完毕:
view plaincopy to clipboardprint?
01.class A {
02. A() {
03. System.out.println("A create");
04. proc();
05. }
06. public void proc() {
07. }
08.}
09.
10.class B extends A {
11. private int i;
12. B() {
13. System.out.println("B create");
14. i = 10;
15. }
16. public void proc(){
17. System.out.println(i);
18. }
19.}
20.
21.public class Main {
22. public static void main(String[] args) {
23. B b = new B();
24. }
25.}
26.输出:
27.A create
28.0
29.B create
class A {
A() {
System.out.println("A create");
proc();
}
public void proc() {
}
}
class B extends A {
private int i;
B() {
System.out.println("B create");
i = 10;
}
public void proc(){
System.out.println(i);
}
}
public class Main {
public static void main(String[] args) {
B b = new B();
}
}
输出:
A create
0
B create
A的构造函数调用了proc,此时B的构造函数还没有被调用,因此i还没有被赋为10,最终输出结果是0。
5. 由于Java对象都是通过垃圾回收机制清理对象,因此Java的类没有析构函数,遇到需要清理类中资源的问题时,可以自己声明一个函数,如Dispose,在适当的时候调用之