2011-05-13 72 views
5
public class Main { 
static final int alex=getc(); 
static final int alex1=Integer.parseInt("10"); 
static final int alex2=getc(); 

public static int getc(){ 
    return alex1; 
} 

public static void main(String[] args) { 
    final Main m = new Main(); 
    System.out.println(alex+" "+alex1 +" "+alex2); 
    } 
} 

有人可以告訴我爲什麼這樣打印:0 10 10?我知道它是一個靜態的最終變量,它的值不應該改變,但它有點難以理解編譯器如何初始化這些字段。初始化Java中的靜態最終字段

回答

3

這種情況是由JLS 8.3.2.3 「關於利用領域的限制初始化期間」 覆蓋。

JLS規則允許在您的問題中使用,並聲明第一次調用getc()將返回默認(未初始化)值alex

但是,規則不允許未初始化變量的某些用途;例如

int i = j + 1; 
int j = i + 1; 

被禁止。


回覆其他答案。這不是Java編譯器「無法解決」的情況。編譯器嚴格執行Java語言規範指定的內容。 (換言之,編譯器可能會編寫來檢測示例中的循環性,並將其稱爲編譯錯誤。但是,如果這樣做,它將拒絕有效的Java程序,因此不會是一個兼容的Java編譯器。)


在評論你的國家,這一點:

...最終場總是必須在編譯或在對象創建之前運行時進行初始化。

這是不正確的。

實際上有2種final領域:

  • 所謂的「恆變量」在編譯時確實評估。 (常量變量是原始類型或類型字符串的變量「,它是最終的,並且使用編譯時常量表達式」 - 參見JLS 4.12.4「進行初始化)。當你訪問它時,這樣的字段總是會被初始化......模仿某些在這裏不相關的併發症。

  • 其他final字段由JLS指定的順序初始化,因此,可以看到該字段的值已初始化之前。 final變量的限制是它們必須初始化期間期間的類初始化(對於static)或期間對象初始化。


最後,這個東西是很 「極端情況」 的行爲。典型的寫作良好的課程在初始化之前不需要 訪問字段final

6

這是一個訂購問題。靜態字段按照遇到的順序進行初始化,所以當您調用getc()初始化alex變量時,alex1尚未設置。你需要首先初始化alex1,然後你會得到預期的結果。

+0

這是一個面試問題不是一個真正的問題,我試圖理解爲什麼編譯器分配0只是因爲alex1字段還沒有initlialized呢??因爲alex1是最終的,而alex代替alex1 = >> alex1是0? – Alexx 2011-05-13 09:02:20

+0

靜態分配與成員變量不同,並且沒有這種保證。評估每個靜態分配,以便類加載器找到它。所以,就你而言,它首先通過調用getc()來指定alex。此時,alex1還沒有初始化,所以返回0。 – stevevls 2011-05-13 09:10:00

+0

好吧,thx.另一個問題..如果它是在靜態塊中初始化的alex1字段,值爲10,其他人打印什麼?哪一個先執行?靜態塊還是初始化? – Alexx 2011-05-13 09:12:07

0

類變量不需要初始化,它們會自動設置爲默認值。如果基元(如int,short ...)對象爲0(零),則它是null。 因此,alex1設置爲0. 方法變量必須被初始化,否則您將收到一個編譯錯誤。

爲了更好地解釋閱讀http://download.oracle.com/javase/tutorial/java/javaOO/classvars.html

+0

是的,但最終字段總是必須在編譯或運行時在對象創建之前初始化。你sayid適用於普通字段而不是最終ones.ps它作品,我說在打印之前'0 10 10' – Alexx 2011-05-13 09:08:08

4

靜態最終字段其值不被編譯時間常數表達式中聲明的順序進行初始化。因此當alex初始化時,alex1尚未初始化,所以getc()返回默認值alex10)。

注意,結果將是不同的(10 10 10)在以下情況下:

​​

在這種情況下alex1由一個編譯時間常量表達式進行初始化,因此它是從一開始就被初始化。

+0

+1對於編譯時常量表達式。 (爲什麼'Integer.parseInt'?) – 2011-05-13 09:18:53

2

靜態字段沒有什麼特別之處,只是編譯器無法鍛鍊您正在使用的方法可以在初始化之前訪問字段。

例如

public class Main { 
    private final int a; 

    public Main() { 
     System.out.println("Before a=10, a="+getA()); 
     this.a = 10; 
     System.out.println("After a=10, a="+getA()); 
    } 

    public int getA() { 
     return a; 
    } 

    public static void main(String... args) { 
     new Main(); 
    } 
} 

打印

Before a=10, a=0 
After a=10, a=10