初始化順序

 
初始化( 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 初始化块。
例如:
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”);
}

}

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");
        }

}



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 );
}
}

稍微解释一下:
首先, 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 ),则对它的引用不会引起定义它的类的初始化。

为了帮助理解最后两点,请试试看下面的例子:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值