2011-03-25 46 views
7

在Java中的for-each循環中使用泛型時出現奇怪的編譯器錯誤。這是一個Java編譯器錯誤,還是我真的在這裏錯過了一些東西?爲什麼Java編譯器抱怨使用foreach與原始類型?

這裏是我的全班同學:

public class Generics<T extends Object> { 
    public Generics(T myObject){ 
    // I didn't really need myObject 
    } 

    public List<String> getList(){ 
    List<String> list = new ArrayList<String>(); 
    list.add("w00t StackOverflow"); 
    return list; 
    } 

    public static void main(String...a){ 
    Generics generics = new Generics(new Object()); 
    for(String s : generics.getList()){ 
     System.out.println(s); 
    } 
    } 
} 

編譯器抱怨與換將線路:「類型不匹配無法從元素類型的對象轉換爲字符串」
如果我讓這個微妙的變化,它編譯:

public static void main(String...a){ 
    Generics<?> generics = new Generics(new Object()); 
    for(String s : generics.getList()){ 
    System.out.println(s); 
    } 
} 

我知道getList()不使用泛型,但它使用它們在我認爲是一個完全無關的方式。我可以理解這一點,如果我試圖迭代T類型的東西,並且getList()返回了List<T>什麼的,但這不是這種情況。 getList()的返回類型應該與T完全無關,不應該在乎我是否使用原始類型作爲我的泛型對象或不是......對嗎?這些不應該完全無關,還是我真的在這裏錯過了一些東西?

注意,代碼也編譯如果我這樣做,我認爲應該是等同於第一以及:

public static void main(String...a){ 
    Generics generics = new Generics(new Object()); 
    List<String> list = generics.getList(); 
    for(String s : list){ 
    System.out.println(s); 
    } 
} 
+1

''沒有比'不同'。你不是在製作你的類的通用版本,而是在製作原始類型。這給我們帶來了一個問題,爲什麼你的類是通用的?你使用T的唯一地方是在構造函數中,你不使用該引用。 – unholysampler 2011-03-25 18:45:20

+0

我用'',因爲我只是需要一些例子。真正的代碼顯然是別的東西,它確實使用T ...它只是以與getList()完全無關的方式使用T。 – 2011-03-25 18:49:34

+0

與你的問題無關,但我會讓構造函數爲泛型cls),所以你不必實例化一個類型爲T的對象來構造這個Generics類。 – MeBigFatGuy 2011-03-25 19:55:26

回答

11

不同之處在於,當您使用原始類型時,全部成員簽名中的通用引用也會轉換爲其原始表單。因此,有效地你打電話現在有這樣一個簽名的方法:

List getList() 

現在,至於爲什麼你的最終版本編譯 - 雖然它,有一個警告,如果您使用-Xlint

Generics.java:16: warning: [unchecked] unchecked conversion 
    List<String> list = generics.getList(); 
             ^

這類似於:

List list = new ArrayList(); 
List<String> strings = list; 

...這也編譯,但-Xlint下一個警告。

故事的寓意:不要使用原始類型!

+0

我很驚訝*成員簽名中的所有通用引用被轉換爲其原始表單。這樣做的理由是什麼(除了Sun感覺就像這樣)? – 2011-03-25 19:49:19

+4

@Michael:JLS在第4.8節(原始類型)中包含了這個討論:「原始類型與通配符密切相關,兩者都基於存在類型。原始類型可以被認爲是通配符,其類型規則故意不適合,以適應與遺留代碼的交互。「換句話說,原始類型通常不應該出現在新代碼中,但他們試圖避免讓舊代碼無法編譯,即使它至少是可疑的。 – 2011-03-25 19:51:40

+0

非常有趣。我已經知道要避免使用原始類型(一個同事寫代碼來聲明變量),但是這突出表明它確實很重要。 – 2011-03-25 20:04:58

3

更改線路

Generics generics = new Generics(new Object()); 

Generics<?> generics = new Generics<Object>(new Object()); 

問題的根源在於您使用的是raw type,所以的類型方法是List,而不是List<String>

+0

泛型不會是字符串類型的泛型......這是整個問題。字符串與泛型類型無關。不管T是什麼,'getList()'應該返回'List '。 – 2011-03-25 18:50:44

+0

@Michael McGowan,好點。但是在聲明處必須有一些與type參數關聯的類型。 '泛型泛型= new泛型(...);'會很好,以不安全的轉換警告爲模。 – 2011-03-25 19:01:56

+0

@Michael McGowan,請注意,如果你所做的只是從類聲明中刪除類型參數'',那麼它就可以工作。 – 2011-03-25 19:03:56

-1

我對你的代碼做了一些調整。 您在您的評論中看到您的構造函數中不需要Object,因此請將其刪除以避免混淆。其次,如果仿製藥將是通用的,正確初始化它

這裏是新的主力將是什麼樣子

public static void main(String...a){ 
    Generics<String> generics = new Generics<String>(); 
    for(String s : generics.getList()){ 
     System.out.println(s); 
    } 
    } 
+0

泛型不會是字符串類型的泛型......這是重點。字符串與泛型類型無關。 – 2011-03-25 18:48:18

+0

我想你誤解了我的觀點。如果你看代碼,你有getList()方法返回一個列表。如果我們想讓代碼非常乾淨,我們可以從getList()方法中的代碼中除去泛型部分。你需要幫助才能編譯,而不是他的方法是對/錯。 – Sean 2011-03-25 19:22:52

+0

如果您在類級別上保留通用減速度,則會打開getList()方法以刪除現在存在的硬編碼。 – Sean 2011-03-25 19:29:34

相關問題