2011-11-14 127 views
2

我不明白爲什麼編譯器在參數化類型定義爲擴展基類時看不到轉換是安全的。這裏有些演員在我看來應該是不必要的。此外,當我包含演員陣容時,我的IDE(IntelliJ IDEA)會警告演員陣容未被選中,好像表明我做錯了什麼。有沒有一種避免這些演員和警告的習語?爲什麼所需的演員,因爲該聲明指出,該類型擴展基類?爲什麼Java強制泛型類型被轉換?

class Shape {} 

class Polygon extends Shape {} 

public class Foo<T extends Shape> 
{ 
    Set<Polygon> polygons; 
    // Why must this be cast? 
    Set<T> shapes = (Set<T>) new HashSet<Polygon>(); 

    T getFirst() 
    { 
    // Why must this be cast? 
    return (T) polygons.iterator().next(); 
    } 

    Iterable<T> getShapes() 
    { 
    // Why must this be cast? 
    return (Iterable<T>) polygons; 
    } 
} 

回答

5

讓我們假設你已經實例化類是這樣的:

Foo<Circle> circleFoo = new Foo<Circle>(); 

然後,Set<Circle>不能安全地分配HashSet<Polygon>

getFirst:你不能安全投PolygonCircle

而在getShapes:你不能安全地投Iterable<Polygon>Iterable<Circle>

+0

改進的拼寫:P –

+0

我在某一時刻理解了這一點。感謝您的簡潔複習。 –

0

在第一示例中,Set<T>不是基類的HashSet<Polygon>

在第二個示例中,polygons.iterator().next()的類型是Polygon,與T不一樣。

5

T延伸形狀,多邊形延伸形狀。 所以沒有理由是t擴展多邊形

1

您可能有興趣閱讀關於Java泛型的this

基本上,

Box<Integer> and Box<Double> are not subtypes of Box<Number> 
1
Set<T> shapes = (Set<T>) new HashSet<Polygon>(); 

強制轉換爲需要在這裏T可以是任何擴展Shape和你想只適合多邊形。 Circleshape但它不是Polygon。最佳做法是將參數化的泛型視爲一個獨特的類。

如果java在沒有演員的情況下允許上述情況,那麼它將爲set添加任何T開門。假設您將Polygon設置爲Set<T>,然後將Circle對象添加到該對象。這引發了很多運行時問題。

1
// Why must this be cast? 
Set<T> shapes = (Set<T>) new HashSet<Polygon>(); 

這是你問題最少的問題。轉換實際上是邏輯上不正確。如果A和B不同,即使A是B的子類型,Set<A>也不是Set<B>的子類型。如果我們具有可定義的泛型,則此投射將失敗。

+0

我現在看到了。這個代碼只有在'Foo'類用類型參數'Shape'或'Polygon'實例化的情況下才是正確的。 FWIW,我正在使用一個API,類型爲「Class '的參數被傳入並在您調用clazz.isAssignableFrom(Polygon。類)'來確定哪些演員是安全的。 –

相關問題