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

在研究另一个问题时,我碰到了1.8.0_112 Sun-Oracle编译器的这种有趣的行为(我没有和其他人一起测试过):

import java.util.List; interface Alpha { List intList(); } interface Beta { List intList(); } class Main { public static void main(String[] args) { Alpha rawAlpha = null; Alpha 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()) {} } } 

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

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

因此,尽管Alpha中的intList()返回列表类型List不依赖于类型参数T ,但似乎在编译时删除了

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

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

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

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

因此,由于rawAlpha是原始类型,因此rawAlpha的类型是List intList()的擦除。 该擦除是List intList()

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