【问题标题】:Non-generic reference to generic class results in non-generic return types对泛型类的非泛型引用导致非泛型返回类型
【发布时间】:2010-10-01 17:40:33
【问题描述】:

我有一个遗留类,该类本身不是泛型,但它的方法之一返回类型使用泛型:

public class Thing {
    public Collection<String> getStuff() { ... }
}

getStuff() 使用泛型返回字符串集合。因此我可以遍历getStuff(),并且无需将元素转换为String

Thing t = new Thing();
for (String s: t.getStuff())  // valid
{ ... }

但是,如果我将 Thing 本身更改为通用但保持其他所有内容相同:

public class Thing<T> {
    public Collection<String> getStuff() { ... }
}

然后继续使用对Thing 的非泛型引用,getStuff() 不再返回Collection&lt;String&gt;,而是返回一个非类型化的Collection。因此客户端代码无法编译:

Thing t = new Thing();
for (String s: t.getStuff())  // compiler complains that Object can't be cast to String
{ ... }

这是为什么?有什么解决办法?

我的猜测是,通过使用对泛型类的非泛型引用,Java 会关闭整个类的所有泛型。这很痛苦,因为现在我通过将 Thing 设为泛型来破坏我的客户端代码。

编辑:我正在为上面示例代码中未列出的另一种方法制作通用的东西。我的问题是关于为什么上述不能完成的教育问题。

【问题讨论】:

    标签: java generics


    【解决方案1】:

    我认为这是完全正常的。在我看来,使用 Thing t = new Thing();对于泛型启用类是完全错误的。当编译器看到一个泛型类被用作没有类型参数的类时,它认为它必须从该类中删除所有泛型类型。这就是如何在新的 Java 编译器中不使用泛型编译旧代码的方法,并且编译器让旧代码使用启用泛型的类(例如 java.util.ArrayList)没有任何问题。 (这就是 java 不需要像 C# 那样分离 System.Collection.Generic.List 和 System.Collection.List 的方式)。您可以运行Thing t = new Thing();,并在其上添加一个简单的类型参数Thing&lt;Object&gt; t = new Thing&lt;Object&gt;();,Java 编译器只需要确保您有意识地使用Java 泛型。我永远不能责怪 Java 出色的向后兼容性。

    我知道我来晚了:D

    【讨论】:

      【解决方案2】:

      好吧,拿两个,我误解了你的问题。

      当您 delcare Thing(这称为 原始类型)而不是 Thing&lt;?&gt;参数化类型)时,Java 编译器会删除所有泛型参数,甚至尽管(如您的情况)方法的泛型类型与类的泛型类型无关。

      来自(优秀的)Java Generics FAQ

      Can I use a raw type like any other type?

      原始类型的方法或构造函数具有类型擦除后的签名。

      这个看似无害且不显眼的句子描述了所讨论的行为。您使用 Thing 作为原始类型,因此返回类型是 Collection(不是 Collection&lt;String&gt;),因为这是类型擦除后的类型。

      困惑?不奇怪。只要看看那个常见问题的大小。地球上大概有三个人了解 Java 泛型的全部含义。想想我最喜欢的 JDK 声明:

      Enum<T extends Enum<T>> 
      

      (FAQ 中也有解释)。

      【讨论】:

      • 由于另一种方法(未在我的示例中列出),我将 Thing 设为通用。
      • 如果事物是​​事物(而不是事物>),它将无法编译。来试试吧。
      • 误解了问题,改了。
      • @Jon:这一切都源于保留向后兼容性(类型擦除)的决定。 Java 人发现 C# 中的 IEnumerable 和 IEnumerable 之类的东西彼此没有关系有点奇怪。
      【解决方案3】:

      由于擦除而失败。您可以在这些Java Tutorials

      中了解更多信息

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-16
        • 1970-01-01
        • 2015-07-30
        • 2011-10-08
        • 1970-01-01
        • 2011-08-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多