学习过面向对象程序设计语言的人都知道,类的构造函数用来初始化对象的。C++有三种类型的构造器:默认构造函数、拷贝构造函数、带参构造函数,Java中只有两种也就是C++的前两种。在学习类的时候,书本或者资料都会这么说:类都要有构造器,它是用来初始化类的对象的。下面笔者要介绍一下,构造器究竟干了什么?
public class Test {
public static void main(String args[]) {
new Test();
}
public Test() {
System.out.println("Test()");
obj1 = new Obj(4);
obj2 = new Obj(5);
obj3 = new Obj(6);
}
public Obj obj1 = new Obj(1);
public Obj obj2 = new Obj(2);
public Obj obj3 = new Obj();
}
class Obj {
public Obj() {
System.out.println("Obj()");
}
public Obj(int a) {
this.a = a; <pre name="code" class="java"> System.out.println("Obj(" + a + ")");
}
public int a;
}
上面就是一个非常简单的代码。执行构造器的时候,肯定会打印出:
Test()
Obj(4)
Obj(5)
Obj(6)
但是实际编译并且运行一下,会发现程序输出结果是:
Obj(1)
Obj(2)
Obj()
Test()
Obj(4)
Obj(5)
Obj(6)
很明显,构造器并不是先被调用的。其实早在构造器执行之前,虚拟机早就已经将对象给构造好了(即在堆中分配了内存空间,并且给赋予初始值。基本类型的初始值是0/false;引用类型的初始值是null。),最好才调用了类的构造器。至于在构造器里再给对象的域赋值,那就是后话了。所以,如果在构造器中给域赋值了,那么实际上对象的域已经被初始化两次:一次是在构造器运行之前,一次是在构造器运行时。因此,不要把这一切的工作都认为是构造器完成的。
其实,如果继续追究(也就是对象/类的初始化顺序)的话,就不得不提,静态代码块和构造代码块了。请看笔者专门讲述这一片内容的文章。