2011-11-03 67 views
2

以下兩種情況似乎工作:內部類和字符串在Java中

public class A { 
    private class B { 
     public static final String str = "str"; 
    } 
} 

public class A { 
    private static class B { 
     public static final String str = new String("str"); 
    } 
} 

但是下面給出在評論中指定的錯誤:

public class A {  
    private class B { 
    //The field str cannot be declared static; 
    //static fields can only be declared in static or top level types 
     public static final String str = new String("str"); 
    } 
} 

爲什麼它被允許在前面兩種情況以及爲什麼它會導致上一個問題?

回答

4

這是JLS, section 8.1.3要求的。我從來沒有看到它的原因,但我懷疑一個不是靜態的內部類需要一個外部類的實例,但是聲明作爲靜態破壞了這個概念,並且允許它們會創建一整套其他規則來處理只是這種情況,這被認爲是不值得的。而當它是靜態的,它就像任何其他類一樣,恰好在同一個源文件中。

1

我猜這個限制是由於new String("str")是如何實現的。使用字符串初始化成員可以使用常量池中的條目來完成,但new String("str")需要實際的代碼執行,因此必須使用靜態init方法中的實際字節碼完成此操作。

螺旋式的內部類方案讓我頭痛,只是想着它(它實際上是內部的kludge),所以我不能解釋到底是什麼問題,但我懷疑靜態init方法運行在不適當的時間如上所述,所以或者結果不可靠,或者系統將無法處理由靜態初始化方法中的錯誤導致的異常。

+0

它不僅僅是'new String(...)'。它是任何不是編譯時常量表達式的*初始值設定項。 –

+0

對。 'new String(「literal」)'可能被編譯器認爲是「安全的」並且被允許,但是這樣你就沒有必要的通用規則。 –

0

JLS明確規定了這一限制;看到伊齋的回答。

「爲什麼」的一種可能的解釋是,會有一個期望,即非常量靜態初始化表達式可以引用封閉類中的靜態或非靜態。第一個可能會導致類(靜態)初始化的排序中的概念或實現困難。第二個是不能實現的,並且會導致難以理解的編譯錯誤。 (考慮新手以簡單的方法在靜態/非靜態訪問限制方面經常出現的頻率。)

我認爲他們只是簡單地採取了簡單的路線並且禁止了這一點。 (KISS爲我工作......)他們可能認爲他們可以在稍後的修訂中放寬限制,但是之後沒有看到需要這樣做。