Eclipse ECJ 接受此代码,javac 不接受 - 谁是对的? [英] Eclipse ECJ accepts this code, javac doesn't - who is right?
问题描述
考虑以下 returnsNull
函数和对它的泛型调用:
Consider the following returnsNull
function and a call to it with a generic type:
public static <T> List<T> returnNull(Class<? extends T> clazz) {
return null;
}
public static void main( String[] args )
{
List<AtomicReference<?>> l = returnNull(AtomicReference.class);
}
Eclipse 编译器在设置为 Java 8 时接受它,但 Java 8 中的 javac
拒绝它:
The Eclipse compiler, when set to Java 8, accepts it, but javac
in Java 8 rejects it with:
incompatible types: cannot infer type-variable(s) T
(argument mismatch; java.lang.Class<java.util.concurrent.atomic.AtomicReference> cannot be converted to java.lang.Class<? extends java.util.concurrent.atomic.AtomicReference<?>>)
潜在的区别似乎是给定两个参数化类型 P1
和 P2
,Eclipse 允许从使用原始参数化的外部类型进行转换内部类型:P1<P2>
到外部类型参数化,内部类型的下限带有无界通配符,如 P1
.javac
没有.
The underlying difference seems to be that given a two parameterized types P1<T>
and P2<T>
, Eclipse allows conversion from the outer type parameterized with the raw inner type: P1<P2>
to the outer type parameterized with a lower bound of the of the inner-type with an unbounded wildcard like P1<? extends P2<?>>
. javac
doesn't.
这不仅仅是理论上的思考:如果此代码被接受,它将解决我的泛型过滤问题.
This isn't just a theoretical musing: if this code was accepted it would solve my generics filtering problem.
谁是对的?
推荐答案
适用性推断 ECJ 将
推断为 AtomicReference#RAW
,让我们 returnNull
的签名显示为
During applicability inference ECJ infers <T>
to AtomicReference#RAW
, which let's the signature of returnNull
appear as
List<AtomicReference#RAW> returnNull(Class<? extends AtomicReference#RAW>)
具体步骤是:
- 初始约束:
⟨Class
→ 类⟩
⟨Class
<:类<?扩展 T#0>⟩ ⟨AtomicReference#RAW <= ?扩展 T#0⟩
⟨AtomicReference#RAW <: T#0⟩
AtomicReference#RAW <: T#0
T#0 = AtomicReference#RAW
现在,将
Class
类型的值传递到该方法中没有问题.Now, there's no problem passing a value of type
Class<AtomicReference#RAW>
into that method.(后缀#RAW 是原始类型的实现特定表示,为了清楚起见,在此复制).
调用类型推断:通过将目标类型添加到混合中,我们最终(在 incorporation) 具有以下约束:
⟨AtomicReference#RAW <: AtomicReference>⟩
此约束应减少为 FALSE,但 ecj 减少为 TRUE.由此看来,拒绝该计划似乎是正确的答案.
This constraint should reduce to FALSE, but ecj reduces to TRUE. From this, rejecting the program seems to be the correct answer.
我已向欧洲法院提交了错误 528970 以供进一步调查.
I filed bug 528970 for further investigation in ECJ.
这有点讽刺,因为javac 有一个长期存在的错误 从而错误地假设
T#RAW <: T
.出于兼容性原因,ECJ 明确地将此错误复制到了许多位置,但显然在一个特定的代码位置,情况正好相反:javac 在 ECJ 检查兼容性的地方应用子类型.There is some irony in this, because javac has a long standing bug whereby it wrongly assumes
T#RAW <: T<X>
. For compatibility reasons, ECJ explicitly copied this bug into many locations, but apparently in one particular code location it's the opposite: javac applies subtyping where ECJ checks for compatibility.编辑 2: 一年后,似乎只有在 JLS 在 JDK-8054721.
EDIT 2: One year later it seems that the bug in ECJ can only be fixed after JLS has been improved in and around JDK-8054721.
这篇关于Eclipse ECJ 接受此代码,javac 不接受 - 谁是对的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!