本文对[#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"