【问题标题】:Why does using raw type variables affect signatures without reference to type-parameters? [duplicate]为什么使用原始类型变量会影响签名而不参考类型参数? [复制]
【发布时间】:2017-03-28 18:05:25
【问题描述】:

查看另一个question 我偶然发现了 1.8.0_112 Sun-Oracle 编译器的这种有趣行为(我没有与其他人一起测试过):

import java.util.List;

interface Alpha<T> {
   List<Integer> intList();
}

interface Beta {
   List<Integer> intList();
}

class Main {

   public static void main(String[] args) {

      Alpha rawAlpha = null;
      Alpha<Character> charAlpha = null;
      Alpha<?> qmAlpha = null;
      Beta beta = null;

      for (Integer i : charAlpha.intList()) {}
      for (Integer i : qmAlpha.intList()) {}
      for (Integer i : beta.intList()) {}
      for (Integer i : rawAlpha.intList()) {}
   }
}

编译器only在最后一个for循环失败:

error: incompatible types: Object cannot be converted to Integer
      for (Integer i : rawAlpha.intList()) {}
                                       ^
1 error

因此,尽管Alpha 中的intList() 返回列表类型List&lt;Integer&gt; 不依赖于类型参数T,但似乎&lt;Integer&gt; 在编译时已被删除。

请注意,如果我们声明一个非泛型接口Beta,理论上这相当于引用原始Alpha,则没有问题。

这是预期的行为吗?有人可以指出语言规范中涵盖这一点的段落吗?如果这至少不是一个错误,那么它似乎相当反直觉和非生产性;也许是为了向后可比性而完成的?

【问题讨论】:

  • 当泛型类型被用作原始类型时,它会丢失它的所有泛型,而不仅仅是那些依赖于您没有提供的类型的泛型。
  • @PeterLawrey 是的,似乎是这样,但问题是为什么?
  • 我在 Java 5.0 发布时询问了一位开发人员,在我看来,没有太多资源可以解决问题,除了它是向后兼容的原始类型或这是一个通用的。没有有点生硬,但仍然有一些理智的后备。
  • 为什么?为什么,因为 JLS 是这么说的,当然!
  • 即使在 11 年前,人们已经认识到稀有类型可能是答案。也许他们会在 Java 10 中。

标签: java generics type-erasure erasure


【解决方案1】:

说明这一点(有点不清楚)的 JLS 位在 JLS 4.8

未从其超类或超接口继承的原始类型 C 的构造函数(第 8.8 节)、实例方法(第 8.4 节、第 9.4 节)或非静态字段(第 8.3 节)的类型是原始类型对应于在对应于 C 的泛型声明中擦除其类型。

所以,由于rawAlpha 是一个原始类型,rawAlpha.intList 的类型就是List&lt;Integer&gt; intList() 的擦除。那个擦除是List intList()

至于为什么,我没有方便的引用,但原始类型仅在 Java 中用于向后兼容。这意味着它们只需要像在泛型之前那样工作即可;你所要求的是代码比以前好一点。这不是不合理,但这不是他们决定的。 :-)

【讨论】:

  • mmm...“是原始类型,对应于在对应于 C 的泛型声明中擦除其类型”......我会说文本有点易于解释...... .所以C在这里Alpha&lt;T&gt;对吗?因此文本将显示为“Alpha.intList 的类型是对应于Alpha 对应的通用声明中List&lt;Integer&gt; 擦除的原始类型,所以Alpha&lt;T&gt;...如果它是一个声明为返回@987654331 的方法@ 这句话完全有道理,但 List&lt;Integer&gt;? 为什么在这里删除 T 会影响 Integer
  • @ValentinRuano 因为List&lt;Integer&gt; 的擦除是List -- 擦除意味着no 通用信息被保留,而不仅仅是T 被擦除。这就是你不能问foo instanceof List&lt;Integer&gt;的原因。
  • 我猜你是对的。对我来说,这只是不清楚最后一部分的含义是什么:“在对应于 C 的通用声明中”。在我看来,如果你是对的(如果你愿意的话,可能是 99.9%),那么句子的那一部分可以简单地省略。所以说List&lt;Integer&gt; 的擦除是List 是不够的,但你需要说List&lt;Integer&gt; 的擦除在与Alpha 对应的通用声明中是List 所以Alpha&lt;T&gt; 无论如何,这对我来说再次听起来很不清楚。
  • JLS 语言需要一些时间来适应,但它非常客观,根本不“受解释”。它非常准确地指出,如果使用原始类型,则其所有成员也将被视为原始类型。这就是为什么你得到了你得到的结果,@ValentinRuano。
猜你喜欢
  • 2018-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-12
  • 2012-01-16
  • 2014-01-26
相关资源
最近更新 更多