2017-03-28 31 views
11

展望另一question我撞到了1.8.0_112太阳甲骨文编译器的这个有趣的行为(我还没有与其他人进行测试):为什么使用原始类型变量会影响签名而不参考类型参数?

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()) {} 
    } 
} 

编译器在最后失败的循环:

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

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

请注意,如果我们声明一个非通用接口Beta,理论上相当于参考原始Alpha,则不存在任何问题。

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

+6

当一个泛型类型被用作原始类型时,它将失去所有它的泛型,而不仅仅是那些依赖于你没有提供的类型的泛型。 –

+0

@PeterLawrey是的,这似乎是这种情况,但问题是为什么? –

+1

在Java 5.0发布时,我问过其中一位开发人员,在我看来,除了向后兼容的原始类型或通用类型之外,没有太多的资源来处理这些情况。没有一点原始的,但仍然是一个理智的后备。 –

回答

12

的JLS位,指出这个(有点不清晰)是JLS 4.8

的类型构造函数(§8.8),实例方法(8.4节,第9.4节),或者非静态场未从它的超类或超接口继承的原类型C(§8.3)是对应对应于其类型的擦除中的一般声明原始类型C.

因此,既然rawAlpha是一个原始类型,rawAlpha.intList的类型是List<Integer> intList()的删除。该擦除是List intList()。至于为什么,我没有一个引用方便,但原始类型只是真正的Java向后兼容性。这意味着他们只需要像仿制药之前一样工作;你要求的是代码的功能已经比以前更好一些了。这不是不合理的,但这不是他们决定的。 :-)

+0

mmm ...“是对应于在与C相对应的泛型声明中删除它的类型的原始类型... ...我会说文本是可以解释的。 ..所以C在这里'''Alpha '''对吗?因此文本会读取“'Alpha.intList''的类型'''对应于'''''''''''''''''的泛型声明中对应'''列表''的擦除对应的原始类型' ''Alpha '''...如果是一个声明为返回的方法'''列表 tList()'''''''''''' '''会影响'''Integer''在这里? –

+2

@ValentinRuano因为'List '的擦除是'List' - 擦除意味着_no_通用信息被保留,而不仅仅是'T'被擦除。这就是你不能问'foo instanceof List '的原因。 – yshavit

+0

我想你是对的。对我而言,这并不清楚这最后一部分意味着什么:“在对应于C的通用声明中”。在我看来,如果你是对的(如果你愿意,99.9%),那么这句话的这一部分可以简单地省略。所以说'''List''''的清除是''List''',但你需要说清除'''List ''''''List''是不够的, ''在对应于''''''''''''''''''''''''''''''''''的通用声明中,无论这意味着什么, –

相关问题