2014-05-14 161 views
4

我想了解各種情況下類實例的初始化。
在JLS-7 12.5節中,沒有提到最終實例變量是如何以及何時初始化的?有人能指出我瞭解在實例變量聲明爲final的情況下的行爲嗎?初始化「最終」實例變量

public class Test { 

     public static void main(String args[]){ 

      Child c1 = new Child(); 
     } 
    } 

    class Parent{ 
     final int a =30; 
     Parent(){ 
      System.out.println("From super Contsrutor "+a); 
      meth(); 
     } 
     void meth(){ 
      System.out.println("From super"); 
     } 
    } 

    class Child extends Parent{ 
     final int e=super.a; 
     int b=30; 
     void meth(){ 
      System.out.println("From Sub e=" +e+", b="+b); 
     } 
    } 

是給輸出如下

From super Contsrutor 30 
From Sub e=0,b=0 

凡爲

public class Test { 

    public static void main(String args[]){ 

     Child c1 = new Child(); 
    } 
} 

class Parent{ 
    final int a =30; 
    Parent(){ 
     System.out.println("From super Contsrutor "+a); 
     meth(); 
    } 
    void meth(){ 
     System.out.println("From super"); 
    } 
} 

class Child extends Parent{ 
    final int e=a; 
    void meth(){ 
     System.out.println("From Sub " +e); 
    } 
} 

是給輸出

From super Contsrutor 30 
From Sub 30 
+0

你能發佈實際的代碼嗎? – njzk2

+3

此代碼目前沒有工作,您沒有任何構造函數,因爲'a'不是父類的名稱。 'meth()'方法永遠不會被調用,但它會創建一個輸出。如果你清理代碼,我們可能會更好地幫助你。 –

+0

已更正代碼 – Pushparaj

回答

2

final int e = a; 

constant variableconstant expression。在調用

System.out.println("From Sub e=" +e+", b="+b); 

編譯器可以用它的價值,30替換使用的e

final int e = super.a; 

可變e不是常數可變,因爲super.a不是simple name,因此,該值不能與將不被替換。

+0

「編譯器可以用它的值來代替e的使用,30。」我在哪裏可以找到JLS有關這個常量變量替換..這似乎是隱含的,但我希望看到,在JLS ..因爲如果我們有這樣的類子延伸父母{0} {0} {0} {0}最終int e = a; int b = a; System.out.println(「From Sub,e =」+ e +「,b =」+ b); }我們得到輸出30,0,因爲b不是最終的,因此不是常量變量,因此在編譯時不能被替換。 – Pushparaj

+0

同樣在JLS-7中「在運行時,靜態字段是最終的並且用常量 表達式(§15.28)初始化(§12.4.2)。這也適用於接口中的這​​些字段 (§9.3 .1)這些字段是「常量」,即使通過不正確的程序(第13.4.9節), 也不會被觀察到它們具有其默認初始值(§4.12.5) 「..但他們沒有提到比如最後的變量...... – Pushparaj

+1

@Pushparaj答案是關於字符串文字和字符串連接章節的一部分。在'Parent'構造函數完成後(參見字節碼),在'Child'構造函數中實際初始化了字段'e' _is_,但是在包含常量表達式連接的字符串文字中,這些值在編譯時按原樣使用並且被使用。 –

1

碼的第一片被給予輸出如下

From super Contsrutor 30 
From Sub e=0,b=0 

這是因爲以下原因。

第一件事,當我們做new Child(),兒童類的constrcutor開始執行

但它的第一條語句是默認的超級因此它給父類constrctor通話

現在父類constrcutor有下面的代碼

父(){ System.out.println(「From super Contsrutor」+ a); (); }

所以這裏的父類調用meth()方法,它的調用者實際上是一個子類的子對象,所以它調用子類甲()方法。

現在,當它從超級構造器調用子類甲()方法時,實際上子對象 尚未創建,因此其變量尚未初始化,但我們正在爲a和b打印值。

因此,在子構建者獲得執行完成之後,在獲得分配之前b得到0。

所以改變你的第一段代碼就可以得到想要的結果 即把meth()調用放到子構造器中而不是放在父構造器中。

package com.kb.finalVariables; 

public class Test { 

    public static void main(String args[]){ 

     Child c1 = new Child(); 
    } 
} 

class Parent{ 
    final int a =30; 
    Parent(){ 
     System.out.println("From super Contsrutor "+a); 
     // meth(); 
    } 
    void meth(){ 
     System.out.println("From super"); 
    } 
} 

class Child extends Parent{ 

    final int e=super.a; 
    int b=30; 
    public Child() { 
     meth(); 
    } 
    void meth(){ 
     System.out.println("From Sub e=" +e+", b="+b); 
    } 
} 
1

讓我們找出程序的流程,我已經寫了下面的代碼吧:

package com.test; 

public class Test { 

    public static void main(String args[]) { 
     Child c1 = new Child(); 
    } 
} 

class Parent { 
    final int a = 30; 
    static int count = 0; 
    { 
     System.out.println("Parent initialization block " + ++count); 
    } 
    Parent() { 
     System.out.println("Parent constructor " + ++count); 
     // System.out.println("From super Contsrutor " + a); 
     meth(); 
    } 
    void meth() { 
     // System.out.println("From super"); 
     System.out.println("Parent meth method " + ++count); 
    } 
} 

class Child extends Parent { 
    final int e = super.a; 
    int b = 30; 
    { 
     System.out.println("Child initialization block " + ++count); 
    } 
    public Child() { 
     System.out.println("Child constructor " + ++count); 
    } 
    void meth() { 
     System.out.println("Child meth method " + ++count); 
     // System.out.println("From Sub e=" + e + ", b=" + b); 
    } 
} 

輸出:

Parent initialization block 1 
Parent constructor 2 
Child meth method 3 
Child initialization block 4 
Child constructor 5 

首先記得我寫初始化塊ParentChild類,它在調用before之前tructor。

現在,如果你可以從創作Child對象第一Parent級的輸出看到的是加載到內存中,然後你叫meth方法內Parent構造將在這個時間打電話meth方法Child類,但Child的初始化塊和Child的構造函數不叫這意味着此時b不是初始化爲30而是int默認值0,與e變量的情況相同。