Java创建类对象时对于构造器,静态对象、非静态对象的初始化有一定的顺序,我简单归纳一下:
class classes {
public classes(String n) {
System.out.println("classes constructor. " + n);
}
}
class classOne {
static classes class2 = new classes("class2");
classOne() {
System.out.println("classOne constructor");
}
classes class1 = new classes("class1");
}
class classTwo extends classOne {
classes class3 = new classes("class3");
static classes class4 = new classes("class4");
classTwo() {
System.out.println("classTwo constructor");
}
}
public class Test4 extends classTwo {
classes class5 = new classes("class5");
static classes class6 = new classes("class6");
Test4() {
System.out.println("Test4 constructor");
}
public static void main(String[] args) {
Test4 test4 = new Test4();
}
}
在这个例子中,类classes是为了下面的类创建对象时能有一定的响应,因为在类中创建基本类型时无法在屏幕看到它被创建的消息,因此我使用了classes作为一个标记,当我创建了一个classes对象且在代码中调用时,会得到相应的响应。
classOne是一个基类,它里面包含了一个静态的classes对象,一个非静态的classes对象,一个构造器。calssTwo继承了classOne,同样地,它也有基类的相同类型的数据定义,为了降低两个类之间初始化顺序的偶然性,我加入了主类Test4继承了classTwo,以模拟多层次的继承关系。
现在,在Test4中的main方法中创建一个Test4对象,在屏幕上的输出如下:
classes constructor. class2
classes constructor. class4
classes constructor. class6
classes constructor. class1
classOne constructor
classes constructor. class3
classTwo constructor
classes constructor. class5
Test4 constructor
我简单解读Java对于这段代码初始化的顺序,首先,创建Test4对象指令发出后,Java查找到Test4还有基类ClassTwo,而classTwo还有基类calssOne,假如classOne还有基类(实际上classOne继承了Java中的Object类,这里不做讨论),它会一直查找,知道找到根本的那个类。找完(也可以称作类的加载)之后,开始执行初始化,首先初始化基类的static成员,即是创建class2这个对象的这段代码,接着是初始化基类的导出类中的static成员,这个初始化一直到最后层次的导出类,我们先称它为过程1。现在static成员被初始化完毕,接着再回到基类,也就是本例中的classOne这个类,初始化它的非static成员,然后调用它的构造器,请注意,这个过程一定是非static成员先于构造器,不管它们在代码中的顺序如何。调用完classOne构造器后,来到calssTwo,初始化它的非static成员,调用它的构造器,接着来到下一个导出类Test4,初始化它的非static成员,调用它的构造器,这样一层一层地执行这种指令,如果从classOne到Test4中间还有多个中间类,那么都会执行这种指令。
至此,一个Test4对象的构建就完成了,归纳起来大概就是:
基类static成员 > 导出类1static成员 > 导出类1的导出类static成员 > ..... > 基类非static成员 >
基类构造器 > 导出类1非static成员 > 导出类1构造器 > 导出类1的导出类非static成员 > 导出类1的导出类构造器
> ....非static成员 > ....构造器 > 最底层导出类非static成员 > 最底层导出类构造器
此外,记得我刚才标注的过程1,即初始化static成员的这个过程。当我们第一次创建对象时,这个static成员的初始化过程才会发生,此后如果再次创建对象,过程1不再发生,比如我在Test4的main方法种创建完test4这个对象之后,在它后面再加一行代码:
Test4 test42 = new Test4();
那么针对这行的创建结果,响应就是:
classes constructor. class1
classOne constructor
classes constructor. class3
classTwo constructor
classes constructor. class5
Test4 constructor
也就是不再初始化static成员。
原因大概就是:static成员不属于某个具体的类对象,它属于整个类,因此,static成员的初始化只在类第一次加载时发生,对于本例中创建的test4对象,就是发生了类的第一次加载,因此它执行了初始化static,对于之后的test42对象,类不是第一次加载,因此不执行初始化static成员的指令。
以上代码在命令行以及JavaIDE eclipse中均测试一致。