2016-07-27 234 views
15

我遇到一個問題,詢問 「關於」默認「構造函數,下列哪一項是正確的?」默認構造函數不初始化類的實例成員?

和選項 「它初始化類的實例成員。」 是不正確的選擇。

現在,我的理解是,如果我們有一個代碼,如

Class Test { 
     String name; 
    } 

那麼編譯器創建默認構造函數,看起來像

Class Test { 
     String name; 
     Test(){ 
      super(); 
      name = null; 
     } 
    } 

不是默認的構造函數初始化實例成員名稱= null?

+1

[Java默認構造函數]的可能重複(http://stackoverflow.com/questions/4488716/java-default-constructor) –

+2

'class'在Java中是小寫的。 – kamoroso94

回答

9

類構造函數不是初始化的類,JVM執行此操作。在創建對象的內存之後,該對象的成員默認初始化爲某個可預測的值,這成爲其默認值。

按照specification

  • 每個類變量,實例變量,或陣列組分與默認值進行初始化,創建(§15.9§15.10.2),當它:
    • 對於類型字節,默認值爲零,即(byte)0的值。
    • 對於short類型,默認值爲零,即值爲(short)0
    • 對於int類型,默認值爲零,即0
    • 對於long類型,默認值爲零,即0L
    • 對於浮點類型,默認值爲正零,即0.0f
    • 對於double類型,默認值爲正零,即0.0d
    • 對於char類型,默認值爲空字符,即'\u0000'
    • 對於布爾類型,默認值爲false
    • 對於所有參考類型(§4.3),默認值爲null

你的假設是接近,但事實是,之前的構造函數的參數甚至評估 - 纔可以值甚至分配給每個字段的 - 這些領域已經持有其默認值,並這由JVM完成。

閱讀款§15.9.4瞭解初始化過程是如何進行的

+0

這是否意味着對於編寫良好的非默認構造函數,您的成員會被初始化,然後立即再次更改其值?看起來效率不高。 –

+0

@LightnessRacesinOrbit並非所有的非默認構造函數都會初始化所有成員。 _寫作_是一個有趣的財產來嘗試和評估。 – Gusdor

+0

@LightnessRacesinOrbit:我只爲一個Java實現做出了貢獻,那是多年前的事情,但我們這樣做的方式是分配零編碼內存(並且IIRC將gc歸零內存銷燬)。所以是的,從某種意義上說,與C或C++相比,效率低下,其中存在未初始化的內存。你所付出的是,Java中沒有這樣的東西。但是,它並沒有像將'0'明確地分配給即將被覆蓋的'byte'數據成員那樣糟糕。它全部是'memset',通常在低優先級的線程中。我不知道Oracle是否以同樣的方式做到這一點。 –

1

不,這不是默認的構造函數初始化實例變量爲您服務。每種類型都有一個默認值。在創建對象的那一刻,將使用默認值。

因此,如果您沒有明確初始化實例變量,它們仍將使用隱式定義的默認值。

即0 INT,空爲引用類型..等

然而,值得注意的是,我們不應該想當然地認爲一個默認值,並給出選擇不初始化的變量。


您可以嘗試定義一個空的構造函數,用空實現覆蓋默認構造函數。你會意識到所有的實例變量仍然會被初始化。

3

是不是默認構造函數初始化實例成員name = null

沒有,構造函數被調用畢竟實例變量是由默認值初始化:0primitive numerical typesfalsereference types同等價值的boolean類型,null

4

在Java領域初始化之前的構造函數。這可以通過下面的代碼是很容易證明:

public class MyClass { 

    int myField = initMyField(); 

    MyClass(){ 
     System.out.println("ctor"); 
    } 

    static int initMyField() { 
     System.out.println("init field"); 
     return 1; 
    } 
} 

輸出

init field 
ctor 

你也可以檢查去編譯代碼。

+2

-1這不能證明任何東西。作爲隱含的'super()',可以在構造函數的開始處編譯初始化。 –

+0

實際上,你展示了一個不同的東西:你展示的初始化實際上移動到了類的初始化塊中,在初始化所有參數初始化之後執行初始化塊(在爲對象分配內存之後由JVM完成)在完成這兩個之後,構造函數被調用。 – Falco

+0

'myField','initMyField'。請注意lowerCase。 – glglgl

0

默認構造函數爲對象提供默認值,並且通常在沒有顯式定義構造函數時由編譯器創建。例如

class DefaultTest{ 
int id; 
String name; 

void display(){System.out.println(id+" "+name);} 

public static void main(String args[]){ 
DefaultTest s1=new DefaultTest(); 
DefaultTest s2=new DefaultTest(); 
s1.display(); 
s2.display(); 
} 
} 

NB:由於沒有構造中定義的編譯器將生成一個默認的構造將分配0空值的兩個對象。

-1

不,它不會初始化非原始實例變量。 只有一個原始的get初始化與默認值

Integer nonPrim; 
int prim; 

然後創建對象後nonPrim == null; prim == 0

感謝

1

它。雖然這個問題更多地基於使用。

public class Main { 
    String x; 

    Main() { 
     x = "Init"; 
    } 

    @Override 
    public String toString() { 
     return x; 

    } 

    public static void main(String[] args) { 
     System.out.println(new Main()); 
    } 

} 

輸出繼電器:

Init 
0

每當我們正在執行的Java類,第一靜態控制流將被執行。在靜態控制流,如果我們正在創建一個對象,然後作爲Inatance控制流的一部分的下面的步驟將被執行(在所提到的順序):

  1. 從實例成員(實例變量和實例塊)的鑑定從上到下。
  2. 執行實例變量賦值和實例塊。
  3. 執行構造函數。

因此,在上面的代碼中,即使在執行構造函數之前,實例變量「name」已經被分配給null(引用類型的默認值)。

相關問題