1. 程式人生 > >靜態資料的初始化

靜態資料的初始化

如果資料是靜態的(static),情況並無不同:如果它屬於某個基本型別,而且你也沒有對它
進行初始化,那麼它就會獲得基本型別的標準初值;如果它是一個物件引用,那麼除非你新
建立一個物件,並指派給該引用,否則它就是空值(null)。


如果想在定義處進行初始化,採取的方法與非靜態資料沒什麼不同。無論建立多少個物件,
靜態資料都只佔用一份儲存區域。但是當你要對這個靜態儲存區域進行初始化時,問題就來
了。看看下面這個例子會更清楚一些:


//: c04:StaticInitialization.java
// Specifying initial values in a class definition.
import com.bruceeckel.simpletest.*; 


class Bowl { 
  Bowl(int marker) { 
    System.out.println("Bowl(" + marker +")"); 
  }
void f(int marker) {
    System.out.println("f(" + marker + ")");
  }
}


class Table { 
static Bowl b1 = new Bowl(1);
  Table() { 
    System.out.println("Table()"); 
    b2.f(1);
  }
void f2(int marker) {
    System.out.println("f2(" + marker +")"); 
 
  }
static Bowl b2 = new Bowl(2);
}


class Cupboard { 
  Bowl b3 = new Bowl(3);
static Bowl b4 = new Bowl(4);
  Cupboard() {
    System.out.println("Cupboard()");
    b4.f(2);
  }
void f3(int marker) {
    System.out.println("f3(" + marker +")"); 
  }
static Bowl b5 = new Bowl(5);
}


publicclass StaticInitialization { 
static Test monitor = new Test(); 
publicstatic void main(String[] args) { 
    System.out.println("Creating new Cupboard() in main"); 
new Cupboard(); 
    System.out.println("Creating new Cupboard() in main"); 
new Cupboard(); 
    t2.f2(1);
    t3.f3(1);
    monitor.expect(new String[] { 
"Bowl(1)",
"Bowl(2)",
"Table()",
"f(1)",
"Bowl(4)",
"Bowl(5)",
"Bowl(3)",
"Cupboard()",
"f(2)",
"Creating new Cupboard() in main",
"Bowl(3)",
"Cupboard()",
"f(2)",
"Creating new Cupboard() in main",
"Bowl(3)",
"Cupboard()",
"f(2)",
 






"f2(1)",
"f3(1)"
    });
  }
static Table t2 =new Table();
static Cupboard t3 =new Cupboard(); 
}///:~


Bowl 類使你得以看到類的建立,而 Table 類和 Cupboard 類在它們的類定義中加入了 Bowl
型別的靜態成員。注意,在靜態資料成員定義之前,Cupboard 類先定義了一個 Bowl 型別的
非靜態成員 b3。


由輸出可見,靜態初始化只有在必要時刻才會進行。如果不建立Table 物件,也不引用 Table.b1
或 Table.b2,那麼靜態的 Bowl b1 和 b2 永遠都不會被建立。只有在第一個 Table 物件被建立
(或者第一次訪問靜態資料)的時候,它們才會被初始化。此後,靜態物件不會再次被初始
化。


初始化的順序是先“靜態”,(如果它們尚未因前面的物件建立過程而被初始化),後“非靜
態”。從輸出結果中可以觀察到這一點。


總結一下物件的建立過程會很有幫助。假設有個名為 Dog 的類:


1. 當首次建立型別為 Dog 的物件時(構造器可以看成靜態方法),或者 Dog 類的靜態方法
/靜態域首次被訪問時,Java 直譯器必須查詢類路徑,以定位 Dog.class 檔案。
2. 然後載入 Dog.class(後面會學到,這將建立一個 Class 物件),有關靜態初始化的動作都
會執行。因此,靜態初始化只在 Class 物件首次載入的時候進行一次。
3. 當你用 new Dog( )建立物件的時候,首先將在堆上為 Dog 物件分配足夠的儲存空間。
4. 這塊儲存空間會被清零,這就自動地將 Dog 中的所有基本型別資料設定成了預設值(對
數字來說就是 0,對布林型和字元型也相同),而引用則被設定成了 null。
5. 執行所有出現於域定義處的初始化動作。
6. 執行構造器。正如你將在第 6 章中看到的,這可能會牽涉到很多動作,尤其是涉及繼承

的時候。