本文对[#0x0001]、[#0x0008]、[#0x000B]做统一归纳。
一个类在能够被程序使用之前,必须经历三个准备工作(以下统称为类的执行):
-> 1. loading
-> 2. linking
--> 2.1 verification
--> 2.2 preparation
--> 2.3 resolution (optional)
-> 3. inintialization
在[#0x0008]、[#0x000B]中,我们使用的loading (加载),其实是统指了以上三个步骤。
loading指从.class文件中读取类的binary representation(即类的Class对象)的过程。
verfication过程验证binary representation的结构是否正确。
preparation过程为类的static field申请空间并赋默认值,同时为类的一些内部数据结构(如方法列表) 申请空间。
resolution过程分析类中的引用。resolution过程是一个optional的过程,在resolution过程中可以有不同的loading策略,比如说,在resolve class A的时候,发现class A中有一个class B的引用,此时可以立即加载class B,也可以do nothing。
initialization过程执行static initializer和initializer for static field (i.e. static variable initializer)。如:
private static int i = 5; //static variable initializer
//static initializer
static
{
......
}
以下不属于initialization阶段执行的代码:
private int i = StaticFunction(); //虽然涉及到了static方法,不过field不是static,不能算是static variable initialzer
//虽然是对static field初始化,但这个initializer本身不是static,依旧不能算是static initializer
{
StaticField = xxx;
......
}
由于loading和linking过程是implementation-dependent,且不方便追踪和查看,所以暂不讨论loading和linking的触发条件。以下着重讨论initialization。
initialization三原则:
-> 1. 触发原则:以下三种场景执行之前会触发initialization
--> 创建类的实例(constrcutor or Class.newInstance())
--> 调用类的static方法(包括constructor)
--> 非final的static field is used or assigned
-> 2. 父类原则:子类initialization之前,其direct父类必须initialization,and do it recursively. (p.s. 类实现的接口无需initialization,类实现的接口的父接口亦无需如此)
-> 3. 引发原则:如果子类initialization引发了父类的initialization,而此时父类还没有loading和linking,则父类的loading和linking也会被引发(p.s. 我觉得子类的initialization同样可以引发子类的loading和linking,如果loading和linking还没有执行的话)。
这里需要着重强调的是:loading、linking和initialization都是类的行为(class behavior) (所以initialization执行的都是static),而实例的创建(constructor or Class.newInstance())则是对象行为(object behavior)。
constructor执行的过程:
-> 执行this() or super()
-> 执行initializer和non-static variable initializer
-> 执行constructor的余下部分
回头看[#0x0008]的例子:
//@file Beetle.java
import static java.lang.System.out;
class Insect
{
private int i = 1;
protected int j;
private static int x1 = printInit("static Insect.x1 initialized");
Insect()
{
out.println("Insect constructor");
out.println("i = " + i + ", j = " + j + ", x1 = " + x1);
this.j = 2;
}
static int printInit(String s)
{
out.println(s);
return 3;
}
}
public class Beetle extends Insect
{
private int k = printInit("Beetle.k initialized");
private static int x2 = printInit("static Beetle.x2 initialized");
public Beetle()
{
out.println("Beetle constructor");
out.println("j = " + j + ", k = " + k + ", x2 = " + x2);
}
public static void main(String[] args)
{
Beetle b = new Beetle();
}
}
//output:
/*
static Insect.x1 initialized
static Beetle.x2 initialized
Insect constructor
i = 1, j = 0, x1 = 3
Beetle.k initialized
Beetle constructor
j = 2, k = 3, x2 = 3
*/
-> 访问Insect的main方法,是个static,引发Beetle的loading、linking和initialization,initialization又引发Insect的loading、linking和initialization
--> 执行Insect的initialization,private static int x1( = 3),打印"static Insect.x1 initialized"
--> 执行Beetle的initialization,private static int x2( = 3),打印"static Beetle.x2 initialized"
-> 进入main(),发现constructor
-> 隐式调用super(),转到Insect的constructor
--> Insect已经loading、linking和initialization了,直接执行non-static variable initializer,初始化private int i( = 1)和protected int j( = 0 by default)
--> 执行Insect constructor的余下部分,打印"Insect constructor"和"i = 1, j = 0, x1 = 3",然后j = 2
-> 执行Beetle的non-static variable initializer,初始化private int k( = 3),打印"Beetle.k initialized"
-> 执行Beetle constructor的余下部分,打印"Beetle constructor"和"j = 2, k = 3, x2 = 3"
回头看[#0x000B]的例子:
class Glyph
{
void draw()
{
System.out.println("Glyph.draw()");
}
Glyph()
{
System.out.println("Glyph constructor");
draw();
}
}
class RoundGlyph extends Glyph
{
private int radius = 1;
RoundGlyph(int r)
{
System.out.println("before assignment in constructor, radius = " + radius);
radius = r;
System.out.println("RoundGlyph constructor, radius = " + radius);
}
void draw()
{
System.out.println("RoundGlyph.draw(), radius = " + radius);
}
}
public class PolyConstructors
{
public static void main(String[] args)
{
new RoundGlyph(5);
}
}
//Output:
/*
Glyph constructor
RoundGlyph.draw(), radius = 0
before assignment in constructor, radius = 1
RoundGlyph constructor, radius = 5
*/
-> 访问PolyConstructors的main方法,loading、linking PolyConstructors,进入main,发现RoundGlyph构造器
-> 隐式调用super(),打印"Glyph constructor",执行RoundGlyph的draw()方法,打印"RoundGlyph.draw(), radius = 0" (此时还没有执行到RoundGlyph的non-static variable initializer)
-> 执行RoundGlyph的non-static variable initializer,radius = 1
-> 执行RoundGlyph构造器的余下部分,打印"before assignment in constructor, radius = 1",然后radius = 5,打印"RoundGlyph constructor, radius = 5"