编译器使用泛型方法的null参数表现不同

Eya*_*der 16 java eclipse generics null compilation

以下代码与Eclipse完美编译,但无法使用javac进行编译:

public class HowBizarre {
      public static <P extends Number, T extends P> void doIt(P value) {
      }

      public static void main(String[] args) {
            doIt(null);
      }
}
Run Code Online (Sandbox Code Playgroud)

我简化了代码,所以现在根本不使用T. 不过,我没有看到错误的原因.由于某种原因,javac决定T代表Object,然后抱怨Object不符合T的界限(这是真的):

HowBizarre.java:6:不兼容的类型; 推断类型参数java.lang.Number,java.lang.Object不符合类型变量的范围P(T)

发现:<P,T>无效

要求:无效

       doIt(null);
           ^
Run Code Online (Sandbox Code Playgroud)

请注意,如果我将null参数替换为非null值,则编译正常.

哪个编译器行为正确,为什么?这是其中之一的错误吗?

pol*_*nts 18

问题是由于JLS规范要求必须推断出不可推断的类型参数Object,即使它不满足边界(并因此会触发编译错误).

以下是"错误"报告的摘录(为了清楚起见,已进一步注释):

"Bug"ID 6299211 - 方法类型变量:推断为null

这个程序不编译:

public class Try {
    void m() {
        java.util.Collections.max(null);
    }
}
Run Code Online (Sandbox Code Playgroud)

:关闭,而不是缺陷.

评价:这不是一个BUG.推理算法不能从argument(null)中收集任何信息,并且在对返回值有任何期望的地方不调用该方法.在这种情况下,编译器必须推断出java.lang.Object类型变量.


JLS 15.12.2.8推断未解析的类型参数

然后推断任何尚未推断的剩余类型变量具有类型 Object


但是,Object它不是子类型,Comparable<? super Object>因此不在声明中的类型变量的范围内Collections.max:

<T extendsObject & Comparable<? super T>> T max(Collection<? extends T>)


进一步的探索

使用显式类型参数"修复"问题:

HowBizarre.<Number,Integer>doIt(null); // compiles fine in javac
Run Code Online (Sandbox Code Playgroud)

为了表明这与null参数关系较少,而更多地与类型推理的绝对缺乏信息有关,您可以尝试以下任一声明:

<T,U extends Comparable<T>> void doIt()

<T extends Number,U extends T> void doIt()
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,调用doIt();不编译javac,因为它必须推断UObject按照15.12.2.8,即使这样做会引发编译错误.


关于Eclipse的注意事项

虽然上面的代码片段都没有在某个版本中编译javac,但它们都在某个版本的Eclipse中完成.这将暗示Eclipse的一个错误.众所周知,不同的编译器之间存在分歧.

相关问题

  • 我不同意评价.不应将`null`推断为`Object`.它应该被推断为"匹配的任何东西". (2认同)