2012-01-06 33 views
2

以下代碼有註釋,表示兩條相似的行,其中一條編譯,其中一條不行。是通過設計還是忽略了Java的常量特定類體的非泛型getClass()方法?

public class TestGenericCollections extends TestCase { 
    List<Key<? extends Enum<?>>> keyList; 

    public TestGenericCollections() { 
    keyList = Lists.newArrayList(); 
    } 

    public <T extends Enum<T>> void addEnum(List<T> values) { 
    Preconditions.checkArgument(values.size() > 0); 
    // Signature of Key.get(): 
    // public static <T> Key<T> get(Class<T> type) 

    // the following line compiles without warning or error 
    keyList.add(Key.get(values.get(0).getDeclaringClass())); 
    // The following line fails to compile with this error message in Eclipse: 
    // The method add(Key<? extends Enum<?>>) in the type List<Key<? extends Enum<?>>> 
    // is not applicable for the arguments (Key<capture#1-of ? extends Enum>) 
    keyList.add(Key.get(values.get(0).getClass())); 
    } 

錯誤信息非常有趣。請注意,沒有Enum<?>,這是生的Enum。這意味着任何泛型方法/集合/等。如果想要避免編譯器警告,那麼想要在匿名常量類體上操作的枚舉類型必須放棄泛型並使用註釋@SuppressWarnings(「rawtypes」)。這就是爲什麼這行不會編譯,但它會超過它。 Enum<T>.GetDeclaringClass()正確地返回一個泛型類型,但編譯器創建的每個Enum值不變的匿名常量特定類不會。

那麼,基本原理是什麼?這是一種疏忽嗎?或者說是語言設計者沒有改變EnumEnumgetClass()方法的匿名常量特定類體上的簽名是否類似於他們在將Java泛型添加到語言時所做的那樣?

+0

什麼類是'Key'? – Bohemian 2012-01-06 06:41:55

+0

這是Guice的一部分,但這對於這個目的無關緊要。您可以將集合類型想象爲List >>,你會得到相同的結果。 – 2012-01-06 06:52:08

回答

1

什麼你的建議是有用的。但我不會把它稱之爲疏忽。

getClass()的簽名在語言規範中有特別的定義,並且需要特殊的編譯器處理。

爲了得到你想要的,語言規範需要枚舉的另一個例外。附加規則並不簡單。用例可能不足以證明成本。

-

如果getClass()回報Class<? extends X>而不是Class<? extends |X|>,這將是在大多數情況下,使用了很多更加有用(如在你的例子)。這在理論上是不正確的,但實際上它在直觀使用中是安全的。我們可以自己定義這樣一個getClass()

@SuppressWarnings("unchecked") 
static public <T> Class<? extends T> getClass(T obj) 
{ 
    return (Class<? extends T>)obj.getClass(); 
} 


// compiles 
keyList.add(Key.get(getClass(values.get(0)))); 
+0

謝謝,這解釋了它,我看到這種行爲不是特定於枚舉,任何泛型類型都有這種行爲。我想當我在javadoc中看到getClass()的簽名時,它返回了一個類,我假設它直觀地操作並且沒有深入其中。擦除再次咬傷。 – 2012-01-06 16:59:55

1

Object.getClass()的靜態返回類型是Class<? extends |X|>其中X是對象的靜態類型。 ? extends,因爲對象的實際類型可能是其靜態類型的子類型,並且由於每個泛型聲明只有一個類對象,所以將其擦除|X|。這兩個限制都不適用於(1)final和(2)從不通用的枚舉。因此getDeclaringClass()的靜態返回類型爲Class<X>是合理的。 getClass()未被覆蓋任何地方任何類,因爲它是final

(我認爲這個回答你的問題。)

相關問題