2012-01-16 116 views
4

可能重複:
Why won't this generic java code compile?爲什麼這種(​​錯誤)使用Java泛型不能編譯?

考慮下面的代碼:

import java.util.Collections; 
import java.util.List; 

public class ComeGetSome { 
    //TODO: private final Some<?> some = new Some(); 
    private final Some some = new Some(); 

    public static void main(String[] args) { 
    new ComeGetSome().dude(); 
    } 

    public void dude() { 
    for (String str : some.getSomeStrings()) { //FIXME: does not compile! 
     System.out.println(str); 
    } 
    } 
} 

class Some<T> { 
    public List<String> getSomeStrings() { 
    return Collections.<String> emptyList(); 
    } 
} 

它不會編譯,因爲some.getSomeStrings()返回原始List。但方法簽名指定它返回一個List<String>

不知何故,它涉及Some有一個類型聲明,但被引用爲原始類型的事實。使用對Some<?>的引用修復了此問題。但是這個方法與類中的類型聲明無關!

爲什麼編譯器的行爲如此?

+0

Collections.emptyList ()? – 2012-01-16 23:23:04

+0

另請參閱http://stackoverflow.com/questions/1661068/java-generics-vanishing-type-in​​formation – 2012-01-16 23:24:21

回答

4

如果使用泛型類的原料(無類型)的實例,那麼它被視爲是完全原料,即所有泛型類型的信息被忽略,即使被忽略的類型是相關已省略的泛型類型。

這就是爲什麼這個......

private final Some<?> some = new Some(); 

...修正錯誤 - 它採用了類型版本的Some(儘管是一個通配符)

1

嗯,首先,它如果您實際上沒有使用定義的類型參數,則聲明Some類是沒有意義的。這實際上是問題的根源。您實例化類型的成員字段在此FASION:

private final Some some = new Some(); 

這是一個原料類型的聲明 - 這是一個通用型與它的類型參數冷落。這實際上不僅意味着它自己的類型參數T被丟棄,而且所有都忽略該類方法中使用的泛型類型,包括參數public List<String> getSomeStrings()中的<String>

因此,解決辦法其實很簡單,報價約書亞·布洛克:

不要在新的代碼中使用的原始類型。

爲了使這個混凝土,修復你的建議:

private final Some<?> some = new Some(); 

修復的問題,但實際上生成編譯器警告(未經檢查的操作)。該乾淨辦法是,要麼宣佈的聲明右側的實際類型參數,如:

private final Some<String> some = new Some<String>(); 

你把泛型參數類型可以通過任何你想要的類型,它取決於你打算使用Some類的方式。但如果你真的不需要類型參數,只需刪除它,代碼會工作得很好:

class Some { ... } 

一個側面說明:這是沒有必要明確聲明String參數在此代碼:

return Collections.<String> emptyList(); 

編譯器推斷,從方法簽名的泛型類型,這樣可以簡化代碼這樣:

public List<String> getSomeStrings() { 
    return Collections.emptyList(); 
    } 

編輯: 說起約書亞布洛赫的,有關於他的2011谷歌I/O談這件事的實際一個很好的Java益智遊戲:http://www.youtube.com/watch?v=wbp-3BJWsU8&t=36m04s