初始化和类的加载
类的代码在初次使用时才会加载,这通常是指加载发生在创建类的第一个对象的时候,但是,当访问static域或者调用了此类的static方法,也会加载。构造器也是static方法,所以总之来说,类是在其任何static成员被访问的时候被加载的。
一个Java类A执行的时候,所发生的第一件事就是试图去访问A的main方法,于是加载器会开始启动并找到A.class文件,在加载的时候会找A是否有父类对象,如果存在父类,假设为B。那么会继续加载,不管是否准备创建一个B的对象。
如果B还有父类,会继续向上加载,如此类推。接下来,会进行根基类的static初始化,然后是下一个子类。这样做的原因是为了子类的初始化可能会依赖于父类成员能否被正确初始化。static代码包括static代码块会按照在类里面的顺序依次加载。
到这里,必要的类都已经加载完了,可以创建对象了。此时,对象中的所有基本类型都会被设置为默认值,对象引用会被设置为null。然后,调用根基类的构造器(如果有构造代码块先调用代码块),在基类的构造期完成以后,实例变量也会按照次序被初始化。例如下面的代码,如果打上断点,看看类加载的顺序,应该就差不多了。
package chapter7;
public class TestLoadSequence {
public static void main(String[] args) {
A a = new A();
System.out.println(a);
}
}
class A extends B {
static int i = 5;
int val;
String s;
static {
System.out.println("static A");
System.out.println("static initialization i = " + i);
System.out.println("static initialization j = " + j);
i = 6;
j = 99;
}
public A() {
System.out.println("constructor A");
System.out.println("constructor A: i is " + i);
System.out.println("constructor A: j is " + j);
System.out.println("constructor A: val is " + val);
System.out.println("constructor A: String is " + s);
}
{
System.out.println("val is " + val);
System.out.println("String is " + s);
val = 1;
s = "default";
}
public static void main(String[] args) {
System.out.println("A main");
}
}
class B {
static {
System.out.println("static B");
int j = 5;
System.out.println("static initialization j = " + j);
}
static int j = 6;
public B() {
System.out.println("constructor B");
System.out.println("constructor B: j is " + j);
}
}
/*
output:
static B
static initialization j = 5
static A
static initialization i = 5
static initialization j = 6
constructor B
constructor B: j is 99
val is 0
String is null
constructor A
constructor A: i is 6
constructor A: j is 99
constructor A: val is 1
constructor A: String is default
chapter7.A@7852e922
*