Java與C++變數初始化的對比
Java儘力保證:所有變數在使用前都能得到恰當的初始化
①函數/方法局部變數的初始化
在C/C++中,變數的初始化還是得依賴於程式員的自覺性。對於函數局部變數,編譯器不會為基本類型賦予預設初始值,新手經常會使用未初始化的指標訪問記憶體,導致程式崩潰。對於類對象,編譯器將使用類的預設建構函式對對象進行初始化。而在Java中,對於方法的局部變數,Java以編譯時間錯誤來保證變數在使用前都能得到恰當的初始化。
void f(){ int i ; i ++ ; //Error- - i not initialized}
儘管java編譯器也可以為方法的局部變數賦予一個初值,但局部變數未初始化更有可能是程式員的疏忽,採用預設值反而會掩蓋這種錯誤。
②類資料成員的初始化
C++程式員剛接觸到java的類時可能會很不習慣,java類的資料成員居然可以在定義時就初始化:
public class InitialValues{boolean bool = true;char ch = ‘x’;int i = 999;double d = 3.14;Depth d = new Depth();}
這種方式在java中稱為指定初始化。在指定初始化之前,編譯器還會為這些資料成員進行預設初始化,實際上是把剛分配的對象記憶體都置零。
// java資料成員的預設初始化public class InitialValues{ boolean t; //flase char c; //[] short s; //0 byte b; //0 int i; //0 long l; //0 float f; //0.0 double d; //0.0}
在對象裡定義一個引用,且不將其初始化時,預設初始化為null。這種預設初始化的實現是,在建立(new)一個對象時,在堆上對對象分配足夠的空間之後,這Block Storage空間會被清零,這樣就自動把基本類型的資料成員都設定成了預設值。預設初始化動作之後,才執行指定初始化。也就是說下面的i經曆過被初始化為0後,再賦值為999的過程。
public class InitialValues{int i = 999;}
java也可以使用建構函式來進行初始化,但建構函式的初始化無法阻止指定初始化和預設初始化的進行,而且總是在它們之後,才會執行建構函式初始化。總結起來說,java中資料成員的初始化過程是:
- ① 先預設初始化
- ② 進行定義處的初始化(指定初始化)
- ③ 建構函式初始化
C++禁止在定義資料成員時就進行指定初始化,而且C++也沒有預設初始化。有人會問,下面這段代碼不是預設初始化了嗎?
class Test {public: int i; double b; char ch;};int main(){ Test *t = new Test(); cout << t->b; //輸出0 cout << t->i; //輸出0 cout << t->ch; //輸出[] return 0;}
這實際上是C++的預設建構函式進行的建構函式初始化。當類沒有建構函式時,編譯器會為類聲明並實現一個預設建構函式,預設建構函式將資料成員初始化為預設值。所以C++資料成員的初始值,只能依賴:
成員初始化列表與java的指定初始化相似,也是在進入建構函式函數體之前,對資料成員進行的初始化。在資料成員的初始化順序上,java與C++倒是一致的,定義的順序決定了初始化的順序。
關於static成員的初始化
在java中不允許有static的局部變數,只能夠有static的域,如static資料成員。static資料成員在對象被第一次建立時才會被執行個體化,而且只執行個體化一次。例如:
class StaticTest{ int _a ; StaticTest (int a ){ _a = a; System.out.println("StaticTest("+a+")"); }}class Test{ static StaticTest st1= new StaticTest(1); StaticTest nonSt = new StaticTest(0); static StaticTest st2= new StaticTest(2);}public class Main { public static void main(String[] args) throws Throwable { Test t = new Test(); //直到這個時候, st1與st2才會被執行個體化 }}//程式輸出StaticTest(1)StaticTest(2)StaticTest(0)
從輸出可以看出在Java中,初始化順序是這樣的:先初始化待用資料成員,再初始化非待用資料成員。
在C++中,static資料成員必須在類之外初始化。關於C++的static, 見 。
回到篇首的話。
Java儘力保證:所有變數在使用前都能得到恰當的初始化(《Java編程思想》) pdf下載見
Java在變數初始化上,普通變數以編譯錯誤、成員變數以預設初始化等手段,儘力使所有的變數在使用前都可得到初始化,在安全性上大大強於C++。