程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java類和對象的初始化順序

Java類和對象的初始化順序

編輯:關於JAVA

本文摘錄於http://blog.csdn.Net/socoolfj/archive/2006/05/23/750425.ASPx,並修改例子的代碼,加上自己的見解。

類裝載步驟

在Java中,類裝載器把一個類裝入Java虛擬機中,要經過三個步驟來完成:裝載、鏈接和初始化,其中鏈接又可以分成校驗、准備和解析三步,除了解析外,其它步驟是嚴格按照順序完成的,各個步驟的主要工作如下:

裝載:查找和導入類或接口的二進制數據;

鏈接:執行下面的校驗、准備和解析步驟,其中解析步驟是可以選擇的;

校驗:檢查導入類或接口的二進制數據的正確性;

准備:給類的靜態變量分配並初始化存儲空間;

解析:將符號引用轉成直接引用;

初始化:激活類的靜態變量的初始化Java代碼和靜態Java代碼塊。

其中 初始化(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. public class Demo{
  2. //初始化static fIEld,
  3. //其中= "initialization static field"又叫做static fIEld initializer
  4. private static String str = "initialization static fIEld";
  5. //初始化塊,又叫做static initializer,或 static initialization block
  6. static {
  7. System.out.println("This is static initializer");
  8. }
  9. }

btw,有些書上提到static initializer 和 static fIEld initializer 的概念,與之對應的還有 instance initializer 和 instance variable initializer。例子中的注釋已經解釋了其含義。

(b)初始化接口(initialization of interface),是指初始化定義在該interface中的fIEld。

*注意*

1. initialization classes 時,該class的superclass 將首先被初始化,但其實現的interface則不會。

initialization classes 時,該class的superclass,以及superlcass的superclass 會首先被遞歸地初始化,一直到Java.lang.Object為止。但initialiazation interface的時候,卻不需如此,只會初始化該interface本身。

2. 對於由引用類變量(class field)所引發的初始化,只會初始化真正定義該fIEld的class。

3. 如果一個static fIEld是編譯時常量(compile-time constant),則對它的引用不會引起定義它的類的初始化。

為了幫助理解最後兩點,請試試看下面的例子:

Initialization類

  1. public class Initialization {
  2. static {
  3. System.out.println("Initialization Main class");
  4. }
  5. public static void main(String[] args) {
  6. System.out.println(Sub.y);
  7. System.out.println(Sub.x);
  8. System.out.println(Sub.z);
  9. }
  10. }

Sub類

  1. public class Sub extends Super {
  2. public static final int y = 2005;
  3. public static int z;
  4. static {
  5. System.out.println("Initialization Sub");
  6. }
  7. }

Super類

  1. public class Super {
  2. public static int x = 2006;
  3. static {
  4. System.out.println("Initialization Super");
  5. }
  6. }

輸入結果

Initialization Main class 
2005 
Initialization Super 
2006 
Initialization Sub 
0

從這個結果可以看到,

  1. static塊在類中會先執行;(實際上是先加載static成員變量,然後是static代碼塊)
  2. static 的final變量不會引起類的初始化;
  3. 子類Sub引用父類Super裡面的變量,就會引起父類的初始化,但不會引起子類的初始化;
  4. static的成員變量也有默認值。

2. 對象的創建(creation of new class instances)

看例子來說明:

InitializationOrder類

  1. public class InitializationOrder {
  2. public static void main(String[] args) {
  3. SubClass sb = new SubClass();
  4. }
  5. }

SuperClass類

  1. public class SuperClass{
  2. static {
  3. System.out.println("SuperClass static");
  4. }
  5. SuperClass(String str){
  6. System.out.println(str);
  7. }
  8. }

Interface類

  1. interface Interface{
  2. static SuperClass su = new SuperClass("Interface new SuperClass");
  3. }

SubClass類

  1. public class SubClass extends SuperClass implements Interface{
  2. static {
  3. System.out.println("SubClass static");
  4. }
  5. private SuperClass su = new SuperClass("initialization variable");
  6. SubClass() {
  7. super("super");
  8. new SuperClass("new SuperClass");
  9. }
  10. }

輸出結果

SuperClass static 
SubClass static 
super 
initialization variable 
new SuperClass

解釋一下:

1) Java虛擬機要執行InitializationOrder類中的static 方法main(),這引起了類的初始化。開始初始化InitializationOrder類。具體的步驟略去不說。

2) InitializationOrder類初始化完畢後,開始執行main()方法。語句SubClass sb = new SubClass()將創建一個SubClass對象。加載類SubClass後對其進行類初始化,因為Subclass有一個父類SuperClass,所以先初始化SuperClass類。於是看到輸出“SuperClass static”。

3) SuperClass類初始化完畢後,開始初始化SubClass類,輸出“SubClass static”。

4) 至此,類的加載工作全部完成。開始進入創建SubClass的對象過程。先為SubClass類和其父類SuperClass類分配內存空間,這時Super su 被賦值為null。

5) 執行構造函數SubClass(),執行super(), 調用父類的構造函數,輸出“super”。

6) 初始化SubClass類的成員變量su,輸出“initialization variable”。

7) 繼續執行構造函數的剩余部分,執行new SuperClass("new SuperClass"),輸出“new SuperClass”,這時Super su 被賦值新建對象的引用。

8) 而SubClass雖然實現了接口Interface,但是初始化它的時候並不會引起接口的初始化,所以接口Interface中的static SuperClass su = new SuperClass("Interface new SuperClass")自始至終都沒有被執行到。

所以對象的創建,具體步驟如下:

(1) 所有的成員變量—包括該類,及它的父類中的成員變量--被分配內存空間,並賦予默認值。(這裡是第一次初始化成員變量)

(2) 為所調用的構造函數初始化其參數變量。(如果有參數)

(3) 如果在構造函數中用this 調用了同類中的其他構造函數,則按照步驟(2)~(6)去處理被調用到的構造函數。

(4) 如果在構造函數中用super調用了其父類的構造函數,則按照步驟(2)~(6)去處理被調用到的父類構造函數。

(5) 按照書寫順序,執行instance initializer 和 instance variable initializer來初始化成員變量。(這裡是第二次初始化成員變量)

(6) 按照書寫順序,執行構造函數的其余部分。

*******************

總結:

從類的初始化和對象的創建步驟,可以知道,一個類是先初始化static的變量和static句塊,然後在分配該類以及父類的成員變量的內存空間,賦予默認值,然後開始調用構造函數。而子類和父類之間,則先初始化和創建父類,然後在初始化和創建子類的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved