Eclipse ECJ接受此代码,javac不接受 - 谁是对的?

Bee*_*ope 5 java eclipse javac language-lawyer

考虑以下returnsNull函数并使用泛型类型调用它:

public static <T> List<T> returnNull(Class<? extends T> clazz) {
    return null;
}

public static void main( String[] args )
{
    List<AtomicReference<?>> l = returnNull(AtomicReference.class);
}
Run Code Online (Sandbox Code Playgroud)

Eclipse编译器在设置为Java 8时接受它,但javac在Java 8中拒绝它:

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<?>>)
Run Code Online (Sandbox Code Playgroud)

底层差异似乎是给定两个参数化类型,P1<T>并且P2<T>Eclipse允许从使用原始内部类型参数化的外部类型转换为P1<P2>使用无界通配符的内部类型的下限参数化的外部类型P1<? extends P2<?>>.javac没有.

这不仅仅是一个理论上的思考:如果这个代码被接受,它将解决我的泛型过滤问题.

谁是对的?

Ste*_*ann 4

在适用性推理过程中, ECJ 推断<T>,AtomicReference#RAW这让 的签名returnNull显示为

\n\n
List<AtomicReference#RAW> returnNull(Class<? extends AtomicReference#RAW>)\n
Run Code Online (Sandbox Code Playgroud)\n\n

具体步骤是:

\n\n
    \n
  • 初始约束:\n\n
      \n
    • \xe2\x9f\xa8Class<AtomicReference#RAW> \xe2\x86\x92 Class<? extends T#0>\xe2\x9f\xa9
    • \n
  • \n
  • 减少为:\n\n
      \n
    • \xe2\x9f\xa8Class<AtomicReference#RAW> <: Class<? extends T#0>\xe2\x9f\xa9
    • \n
    • \xe2\x9f\xa8AtomicReference#RAW <= ? extends T#0\xe2\x9f\xa9
    • \n
    • \xe2\x9f\xa8AtomicReference#RAW <: T#0\xe2\x9f\xa9
    • \n
    • AtomicReference#RAW <: T#0
    • \n
  • \n
  • 解决为:\n\n
      \n
    • T#0 = AtomicReference#RAW
    • \n
  • \n
\n\n

现在,将类型值传递到该方法中没有问题Class<AtomicReference#RAW>。

\n\n

(后缀 #RAW 是原始类型的实现特定表示,为了清楚起见,在此处复制)。

\n\n

编辑:在调用类型推断期间事情看起来有所不同:通过将目标类型添加到混合中,我们最终(在合并期间)具有以下约束:

\n\n
    \n
  • \xe2\x9f\xa8AtomicReference#RAW <: AtomicReference<?>\xe2\x9f\xa9
  • \n
\n\n

此约束应减少为 FALSE,但 ecj 减少为 TRUE。由此看来,拒绝该计划似乎才是正确的答案。

\n\n

我向 ECJ 提交了错误 528970以便进一步调查。

\n\n

这有一些讽刺意味,因为javac 有一个长期存在的错误,它错误地假设T#RAW <: T<X>. 出于兼容性原因,ECJ 明确将此错误复制到许多位置,但显然在一个特定代码位置,情况恰恰相反:javac 在 ECJ 检查兼容性的位置应用子类型。

\n\n

编辑2:一年后,ECJ 中的错误似乎只能在 JLS 在JDK-8054721及其周围进行改进后才能修复。

\n