为什么Java强制使用泛型类型?

时间:2011-11-14 16:00:40

标签: java generics collections casting

我不明白为什么当参数化类型被定义为扩展基类时,编译器无法看到强制转换是安全的。以下是演员的例子,在我看来他们应该是不必要的。此外,当我确实包含演员表时,我的IDE(IntelliJ IDEA)会警告演员表未经检查,好像是表明我做错了。有没有避免这些演员和警告的成语?为什么需要强制转换,因为声明声明类型扩展了基类?

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;
  }
}

6 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:5)

我们假设你已经像这样实例化了你的类:

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

然后,Set<Circle>无法安全地分配HashSet<Polygon>

getFirst中:您无法安全地将Polygon投射到Circle

getShapes中:您无法安全地将Iterable<Polygon>投射到Iterable<Circle>

答案 2 :(得分:1)

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

基本上,

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

答案 3 :(得分:1)

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

需要强制转换为T此处可以是任何扩展Shape并且您尝试仅适合多边形的内容。 Circleshape,但不是Polygon。最佳实践是将参数化泛型视为唯一类。

如果java在没有强制转换的情况下允许上述内容,则会打开一扇门,将T添加到set。想象一下,您已将Polygon集分配给Set<T>,然后向其添加了Circle个对象。这引发了许多运行时问题。

答案 4 :(得分:1)

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

这是你遇到的最少的问题。转换实际上逻辑上不正确。如果A和B不同,Set<A>不是Set<B>的子类型,即使A是B的子类型。如果我们有可再生的泛型,那么这个演员会失败。

答案 5 :(得分:0)

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

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