为什么Java强制泛型类型被转换?

问题描述:

我不明白为什么编译器在参数化类型定义为扩展基类时看不到转换是安全的。这里有些演员在我看来应该是不必要的。此外,当我包含演员阵容时,我的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; 
    } 
} 

让我们假设你已经实例化类是这样的:

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

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

getFirst:你不能安全投PolygonCircle

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

+0

改进的拼写:P –

+0

我在某一时刻理解了这一点。感谢您的简洁复习。 –

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

在第二个示例中,polygons.iterator().next()的类型是Polygon,与T不一样。

T延伸形状,多边形延伸形状。 所以没有理由是t扩展多边形

您可能有兴趣阅读关于Java泛型的this

基本上,

Box<Integer> and Box<Double> are not subtypes of Box<Number> 

Set<T> shapes = (Set<T>) new HashSet<Polygon>(); 

强制转换为需要在这里T可以是任何扩展Shape和你想只适合多边形。 Circleshape但它不是Polygon。最佳做法是将参数化的泛型视为一个独特的类。

如果java在没有演员的情况下允许上述情况,那么它将为set添加任何T开门。假设您将Polygon设置为Set<T>,然后将Circle对象添加到该对象。这引发了很多运行时问题。

// 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。类)'来确定哪些演员是安全的。 –