2014-10-02 84 views
5

如果我舉個例子,有一個使用可變參數的類類型的擴展超類像 這樣的方法:可變參數

public static <E extends Example> void test(Class<E>... es){} 

然後我嘗試調用該方法有兩種不同的例子的子類,我只能這樣做,如果我用它的兩個類的數組。

//this does not work 
test(E1.class,E2.class); 
//this does work 
test(new Class[]{E1.class,E2.class}); 
public class E1 extends Example {} 
public class E2 extends Example {} 

這是爲什麼?

回答

6

此行不會編譯:

test(E1.class,E2.class); 

只有一種類型參數E和Java必須準確推斷的參數類型相匹配。它不能推斷出Example,因爲對象是Class<E1>Class<E2>,而不是Class<Example>。 Java泛型的不變性防止了這種情況的發生。

您可以解決此通過引入上test的泛型類型參數的上限通配符:

public static <E extends Example> void test(Class<? extends E>... es) 

這使得Java推斷ExampleE,通過滿足與E1E2上限通配符。

第二行創建一個Class es的原始數組,繞過泛型並生成「未經檢查的調用」警告。

new Class[]{E1.class,E2.class} 

如果你試圖提供一個類型參數Class在這裏,你會得到一個編譯器錯誤與任何中途合理的類型參數:

// Needs Class<Example> but found Class<E1> and Class<E2> 
test(new Class<Example>[]{E1.class,E2.class}); 

// Needs Class<E1> but found Class<E2> 
test(new Class<E1>[]{E1.class,E2.class}); 

// Needs Class<E2> but found Class<E1> 
test(new Class<E2>[]{E1.class,E2.class}); 

通過使用通配符通過滿足推理這裏只是揭示了真正的問題 - 通用數組的創建。

// Generic array creation 
test(new Class<? extends Example>[]{E1.class,E2.class}); 
+0

非常感謝。這對我的計劃永遠不會造成傷害,但我一直在爲此撓頭。我非常感謝澄清。 – Squirvin 2014-10-03 01:47:53

2

您可以定義擴展Example的單個類的泛型E.你不能在你的呼叫中引用兩個不同的類,因爲它不知道E是什麼類型。它只期望一種類型。

雖然這不起作用:

test(E1.class, E2.class); 

這並不:

test(E1.class, E1.class); 

你可以用一個數組做到這一點的原因是因爲類型擦除。編譯器沒有看到數組中的類是不同的。

如果你改變你的方法來接受任何延伸Example的類,它就會工作。

public static void test(Class<? extends Example>...classes) 
+1

我想你已經解釋得很好。但要等同於OP的示例,您的簽名應該是'public static void test(Class ... classes)''。它會(無論如何)發出'-Xlint:unchecked'警告。 – 5gon12eder 2014-10-02 22:16:27

+0

@ 5gon12eder:你給出的簽名和這個回答中的簽名完全相同,即他們接受完全相同的參數類。更簡單的(在這個答案中給出的)應該總是首選的,因爲類型參數是不必要的。 – newacct 2014-10-03 03:32:37

+0

@newacct它們接受相同類型的參數,但如果要引用泛型類型,則需要更詳細的語法。由於在OP中,'test'返回'void'並且有一個空體,所以您可能會爭辯說我們不希望引用該類型,但通常來說,冗長的語法也更加強大。 – 5gon12eder 2014-10-03 03:42:17