【问题标题】:Why does Java force generic types to be cast?为什么 Java 强制转换泛型类型?
【发布时间】:2011-12-28 18:52:13
【问题描述】:

我不明白为什么当参数化类型被定义为扩展基类时编译器看不到强制转换是安全的。以下是在我看来应该是不必要的演员表示例。此外,当我确实包含演员表时,我的 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;
  }
}

【问题讨论】:

    标签: java generics collections casting


    【解决方案1】:

    假设您已经像这样实例化了您的类:

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

    那么,Set&lt;Circle&gt; 不能安全地分配给HashSet&lt;Polygon&gt;

    getFirst:您不能安全地将Polygon 转换为Circle

    getShapes 中:您不能安全地将Iterable&lt;Polygon&gt; 转换为Iterable&lt;Circle&gt;

    【讨论】:

    • 我一度明白这一点。感谢您简洁的复习。
    【解决方案2】:

    T 扩展 Shape,Polygon 扩展 Shape。 所以 T 没有理由扩展 Polygon

    【讨论】:

      【解决方案3】:

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

      基本上,

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

      【讨论】:

        【解决方案4】:
        Set<T> shapes = (Set<T>) new HashSet<Polygon>();
        

        需要一个演员表,因为T 可以是扩展Shape 的任何东西,并且您试图只适合多边形。 Circleshape,但不是 Polygon。最佳实践是将参数化泛型视为唯一类。

        如果 java 在没有演员表的情况下允许上述内容,那么它将打开一扇门,可以将任何 T 添加到 set。想象一下,您将 Polygon 集分配给 Set&lt;T&gt;,然后将 Circle 对象添加到其中。这会引发很多运行时问题。

        【讨论】:

          【解决方案5】:
          // Why must this be cast?
          Set<T> shapes = (Set<T>) new HashSet<Polygon>(); 
          

          这是您遇到的最少的问题。这种转换实际上是逻辑上不正确的Set&lt;A&gt; 不是 Set&lt;B&gt; 的子类型,如果 A 和 B 不同,即使 A 是 B 的子类型。如果我们有可具体化的泛型,这个转换就会失败。

          【讨论】:

          • 我现在明白了。此代码仅在使用类型参数ShapePolygon 实例化类Foo 的情况下是正确的。 FWIW,我正在使用一个 api,其中传入了 Class&lt;T&gt; 类型的参数,并在您调用 clazz.isAssignableFrom(Polygon.class) 的方法内确定哪些强制转换是安全的。
          【解决方案6】:

          在第一个示例中,Set&lt;T&gt; 不是HashSet&lt;Polygon&gt; 的基类。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-02-04
            • 1970-01-01
            • 2021-09-11
            • 1970-01-01
            • 2016-07-12
            • 1970-01-01
            相关资源
            最近更新 更多