初始化(
initialization
)其实包含两部分:
1. 类的初始化( initialization class & interface )
2. 对象的创建( creation of new class instances )。
因为类的初始化其实是类加载( loading of classes )的最后一步,所以很多书中把它归结为 “ 对象的创建 ” 的第一步。 其实只是看问题的角度不同而已。为了更清楚的理解,这里还是分开来。
顺序:
应为类的加载肯定是第一步的,所以类的初始化在前 , 大体的初始化顺序是:
类初始化 -> 子类构造函数 -> 父类构造函数 -> 实例化成员变量 -> 继续执行子类构造函数的语句
下面结合例子,具体解释一下。
1 。类的初始化( Initialization classes and interfaces ),其实很简单,具体来说有:
( a )初始化类( initialization of class ),是指初始化 static field 和执行 static 初始化块。
例如:
1. 类的初始化( initialization class & interface )
2. 对象的创建( creation of new class instances )。
因为类的初始化其实是类加载( loading of classes )的最后一步,所以很多书中把它归结为 “ 对象的创建 ” 的第一步。 其实只是看问题的角度不同而已。为了更清楚的理解,这里还是分开来。
顺序:
应为类的加载肯定是第一步的,所以类的初始化在前 , 大体的初始化顺序是:
类初始化 -> 子类构造函数 -> 父类构造函数 -> 实例化成员变量 -> 继续执行子类构造函数的语句
下面结合例子,具体解释一下。
1 。类的初始化( Initialization classes and interfaces ),其实很简单,具体来说有:
( a )初始化类( initialization of class ),是指初始化 static field 和执行 static 初始化块。
例如:
class
Super
...
{
static String s = “initialization static field”; //初始化static field,其中“= “initialization static field” ”又叫做static field initializer
// static初始化块,又叫做static initializer,或 static initialization block
static ...{
System.out.println(“This is static initializer”);
}
}
static String s = “initialization static field”; //初始化static field,其中“= “initialization static field” ”又叫做static field initializer
// static初始化块,又叫做static initializer,或 static initialization block
static ...{
System.out.println(“This is static initializer”);
}
}
public
class
Initialization
...
{
public static void main(String[] args) ...{
System.out.println(Sub.x); // Won't cause initialization of Sub, because x is declared by S, not Sub.
// 不会引起Sub类的初始化,因为x是定义在Super类中的
System.out.println("-------------------------");
System.out.println(Sub.y); // Won't cause initialization of Sub, because y is constant.
// 不会引起Sub类的初始化,因为y是常量
System.out.println("-------------------------");
System.out.println(Sub.z = 2004); // Will cause initialization of Sub class
// 将会引起Sub的初始化
}
}
class Super ... {
static int x = 2006;
}
class Sub extends Super ... {
static final int y = 2005;
static int z;
static ...{
System.out.println("Initialization Sub");
}
}
public static void main(String[] args) ...{
System.out.println(Sub.x); // Won't cause initialization of Sub, because x is declared by S, not Sub.
// 不会引起Sub类的初始化,因为x是定义在Super类中的
System.out.println("-------------------------");
System.out.println(Sub.y); // Won't cause initialization of Sub, because y is constant.
// 不会引起Sub类的初始化,因为y是常量
System.out.println("-------------------------");
System.out.println(Sub.z = 2004); // Will cause initialization of Sub class
// 将会引起Sub的初始化
}
}
class Super ... {
static int x = 2006;
}
class Sub extends Super ... {
static final int y = 2005;
static int z;
static ...{
System.out.println("Initialization Sub");
}
}
2 。对象的创建( creation of new class instances ),稍微有点烦琐,具体的步骤如下
(a) 所有的成员变量 — 包括该类,及它的父类中的成员变量 -- 被分配内存空间,并赋予默认值。 ( Btw ,这里是第一次初始化成员变量)
(b) 为所调用的构造函数初始化其参数变量。(如果有参数)
(c) 如果在构造函数中用 this 调用了同类中的其他构造函数,则按照步骤 (b)~(f) 去处理被调用到的构造函数。
(d) 如果在构造函数中用 super 调用了其父类的构造函数,则按照步骤 (b)~(f) 去处理被调用到的父类构造函数。
(e) 按照书写顺序,执行 instance initializer 和 instance variable initializer 来初始化成员变量。( Btw ,这里是第二次初始化成员变量)
(f) 按照书写顺序,执行 constructor 的其余部分。
* 注意 *
成员变量其实都被初始化 2 次,第一次是赋予默认值,第二次才是你想要设定的值。
最后看一个例子:
public
class
InitializationOrder {
public static void main(String[] args) {
Subclass sb = new Subclass();
}
}
class Super{
static {
System. out .println( 1 );
}
Super( int i){
System. out .println(i);
}
}
class Subclass extends Super implements Interface{
static {
System. out .println( 2 );
}
Super su = new Super( 4 );
Subclass() {
super( 3 );
new Super( 5 );
}
}
interface Interface{
static Super su = new Super( 0 );
}
public static void main(String[] args) {
Subclass sb = new Subclass();
}
}
class Super{
static {
System. out .println( 1 );
}
Super( int i){
System. out .println(i);
}
}
class Subclass extends Super implements Interface{
static {
System. out .println( 2 );
}
Super su = new Super( 4 );
Subclass() {
super( 3 );
new Super( 5 );
}
}
interface Interface{
static Super su = new Super( 0 );
}
稍微解释一下:
首先, Java 虚拟机要执行 InitializationOrder 类中的 static 方法 main() ,这引起了类的初始化。开始初始化 InitializationOrder 类。具体的步骤略去不说。
接着, InitializationOrder 类初始化完毕后,开始执行 main() 方法。语句 Subclass sb = new Subclass() 将创建一个 Subclass 对象。加载类 Subclass 后对其进行类初始化,但因为 Subclass 有一个父类 Super ,所以先初始化 Super 类,初始化块 static {System.out.println(1);} 被执行,打印输出 1 ;
第三, Super 初始化完毕后,开始初始化 Subclass 类。 static {System.out.println(2);} 被执行,打印输出 2 ;
第四,至此,类的加载工作全部完成。开始进入创建 Subclass 的对象过程。先为 Subclass 类和其父类 Super 类分配内存空间,这时 Super su 被附值为 null;
第五,执行构造函数 Subclass() 时, super(3) 被执行。如前面 (d) 所说, Super 类的构造函数 Super(int i){….} 被调用,并按照步骤 (b)~(f) 来处理。 因此,递归调用 Super 类的父类 Object 类的构造函数,并按照步骤 (b)~(f) 来初始化 Object 类,不过没有任何输入结果。最后打印输出 3 ;
第六,如前面 (e) 所说,初始化成员变量 su ,其结果是打印输出 4 ;
第七,如前面 (f) 所说,执行 new Super(5) ,并打印输出 5 ;
最后, Subclass 虽然实现了接口 Interface ,但是初始化它的时候并不会引起接口的初始化,所以接口 Interface 中的 static Super su = new Super(0) 自始至终都没有被执行到。
btw ,有些书上提到 static initializer 和 static field initializer 的概念,与之对应的还有 instance initializer 和 instance variable initializer 。例子中的注释已经解释了其含义。
( b )初始化接口( initialization of interface ),是指初始化定义在该 interface 中的 field 。
* 注意 *
--initialization classes 时,该 class 的 superclass 将首先被初始化,但其实现的 interface 则不会。
--initialization classes 时,该 class 的 superclass ,以及 superlcass 的 superclass 会首先被递归地初始化,一直到 java.lang.Object 为止。但 initialiazation interface 的时候,却不需如此,只会初始化该 interface 本身。
-- 对于由引用类变量( class field )所引发的初始化,只会初始化真正定义该 field 的 class 。
-- 如果一个 static field 是编译时常量( compile-time constant ),则对它的引用不会引起定义它的类的初始化。
为了帮助理解最后两点,请试试看下面的例子: