为什么使用原始类型变量会影响签名而不引用类型参数?

Val*_*ano 11 java generics type-erasure erasure

在研究另一个问题时,我碰到了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()) {}
   }
}
Run Code Online (Sandbox Code Playgroud)

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

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

所以,尽管intList()返回列表类型List<Integer>Alpha不依赖于类型参数T,似乎<Integer>是在编译时间删除.

请注意,如果我们声明一个非泛型接口Beta,理论上相当于引用raw Alpha,那就没有问题.

这是预期的行为吗?是否有人能指出涵盖这一点的语言规范段落?如果这不是一个错误,它至少看起来反直觉和非生产性; 或许是为了背部可比性而做的?

ysh*_*vit 12

说这个(有点不清楚)的JLS位在JLS 4.8中:

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

所以,既然rawAlpha是原始类型,那么类型rawAlpha.intList就是擦除List<Integer> intList().那个擦除是List intList().

至于为什么,我没有引用方便,但原始类型只是用于向后兼容的Java.这意味着他们只需要像仿制药一样工作; 您要求的是代码,它比以前更好一些.这不是没有道理的,但并不是他们决定的.:-)

  • @ValentinRuano因为`List <Integer>`的擦除是`List` - 擦除意味着_no_通用信息被保留,而不仅仅是'T`被擦除.这就是你不能问`foo instanceof List <Integer>`的原因. (2认同)