2009-01-16 60 views
8

我有一個傳統類的類本身不是一個通用的,但它的方法返回類型使用泛型:非一般引用泛型類導致非泛型返回類型

public class Thing { 
    public Collection<String> getStuff() { ... } 
} 

getStuff()使用泛型返回一組字符串。因此,我可以遍歷getStuff()而且也沒有必要元素轉換爲String

Thing t = new Thing(); 
for (String s: t.getStuff()) // valid 
{ ... } 

但是,如果我改變Thing本身是一個通用的,但保持一切相同:

public class Thing<T> { 
    public Collection<String> getStuff() { ... } 
} 

然後繼續使用非泛型引用Thing,getStuff()不再返回Collection<String>,而是返回一個非類型的Collection。因此客戶端代碼無法編譯:

Thing t = new Thing(); 
for (String s: t.getStuff()) // compiler complains that Object can't be cast to String 
{ ... } 

這是爲什麼?什麼是解決方法?

我的猜測是,通過使用泛型類的非泛型引用,Java關閉了整個類的所有泛型。這很痛苦,因爲現在我已經通過讓Thing成爲通用的代碼來破壞我的客戶端代碼。

編輯:我對Thing通用的另一種方法,沒有在上面的示例代碼中列出。我的問題是教育,爲什麼不能做到上述。

回答

10

好吧,拿兩個,我誤解了你的問題。

當你delcare Thing(這被稱爲原始類型),而不是Thing<?>參數化類型)Java編譯器剔除掉所有通用參數,甚至thogh(如你的情況)泛型類型的方法與類的泛型無關。

從(優秀)Java Generics FAQ

Can I use a raw type like any other type?

方法或原始類型的構造有,他們將不得不類型擦除後的簽名。

這看似無傷大雅和不顯眼的句子描述了有問題的行爲。您使用Thing作爲原始類型,因此返回類型爲Collection(不是Collection<String>),因爲這是類型擦除後的類型。

困惑?不奇怪。看看這個FAQ的大小。世界上大概有三個人理解Java泛型的全部含義。請考慮我最喜歡的來自JDK的聲明:

Enum<T extends Enum<T>> 

(Theres在常見問題解答中也提到了這一點)。

+0

我正在做Thing通用因爲另一種方法(我沒有在我的例子中列出)。 – 2009-01-16 00:38:20

0

由於擦除而失敗。你可以在這些閱讀更多關於它Java Tutorials

0

我認爲這是完全正常的。在我看來,使用Thing t = new Thing();對於通用的類是完全錯誤的。當編譯器看到一個泛型類用作不帶類型參數的類時,它認爲它必須擦除該類中的所有泛型類型。這就是如何在新的Java編譯器和編譯器中不使用泛型的情況下編譯舊代碼,讓舊代碼可以毫無問題地使用通用啓用類(例如java.util.ArrayList)。 (這是如何java不需要像C#分離System.Collection.Generic.List和System.Collection.List)。您可以運行Thing t = new Thing();並在其上添加一個簡單的類型參數,Thing<Object> t = new Thing<Object>();,只有java編譯器需要確保您有意識地使用java通用。我永遠不能責怪Java的極好的向後兼容性。

我知道我有點晚:D