Mik*_*bel 10 java generics intellij-idea
我遇到了一些有趣的Java代码,IntelliJ标记为错误,但javac
接受为合法.IntelliJ是错误的,代码是合法的,或者编译器是"错误的",无论是由于错误还是故意放松规则.
我喜欢把我的理解Java类型系统相当不错,和我自己的推理使我怀疑的IntelliJ是错误的,javac
是对的.但是,我对JLS有一段时间了,我想知道肯定.
在我们讨论有问题的代码之前,让我们看看一些绝对非法的类似代码:
interface A<T> {}
interface X extends A<String> {}
interface Y extends A<Object> {}
interface Z extends X, Y {} // COMPILE ERROR
Run Code Online (Sandbox Code Playgroud)
正如我所料,IntelliJ都javac
正确地将其标记为错误:'A'不能用不同的类型参数继承:'java.lang.String'和'java.lang.Object'.
没问题.但是如果我们通过扩展原始形式来制作X
和Y
通用呢?Z
interface X<T> extends A<String> {}
interface Y<T> extends A<Object> {}
interface Z extends X, Y {} // OK according to javac, ERROR according to IntelliJ
Run Code Online (Sandbox Code Playgroud)
在这里,IntelliJ急切地报告了它为第一个片段所做的相同错误,但很javac
高兴接受所写的代码.
我的理解是原始类型是递归擦除的,这意味着原始类型的所有超类和超接口都被其递归擦除的表单替换,依此类推.因此,在有问题的代码中,Z
最终A
通过两者延伸(原始),X
并且Y
与第一示例相反,其Z
延伸A<String>
通过X
和A<Object>
通过Y
.
如果确实如此,那么我会得出结论,IntelliJ是错误的,并且javac
是正确的:第二个代码片段是合法的.
你怎么说,Stack Overflow的专家?
规范在JLS-8.1.5中说:
类可能不是同一通用接口(第9.1.2节)的不同参数化的两种接口类型的子类型,或通用接口的参数化的子类型和命名相同通用接口的原始类型,或发生编译时错误.
请注意,它特别注意"通用接口的参数化的子类型和相同通用接口的原始类型命名"的情况,这将转换为类似的东西interface Z extends A<String>, A {}
.没有提到2个原始超级接口的情况.
此外,规范给出了这个例子:
Run Code Online (Sandbox Code Playgroud)interface I<T> {} class B implements I<Integer> {} class C extends B implements I<String> {}
C类导致编译时间错误,因为它试图是两者的亚型
I<Integer>
和I<String>
.
问题是,A
被扩展为不同类型的参数,如果X
和Y
它们都对扩大A<Object>
你的第一个片段,还编译.
JLS-4.8说(正如你已经提到的):
原始类型的超类(分别为超级接口)是泛型类型的任何参数化的超类(超接口)的擦除.
这意味着两次Z
扩展原始类型A
,而不是 A
使用不同的参数化.此外,类可以两次具有相同的(间接)超级接口(参见JLS-8.1.5-2中的第二个示例).
所以我得出结论,Intellij在这里是错误的.
归档时间: |
|
查看次数: |
132 次 |
最近记录: |