Java 为什么这个方法重载不明确?

Java 为什么这个方法重载不明确?,java,overloading,wrapper,primitive,jdk1.6,Java,Overloading,Wrapper,Primitive,Jdk1.6,我已经搜索过了,发现加宽优先级高于取消装箱,所以在上面的方法调用中,应该调用第一个方法,因为第二个参数对这两个方法都是相同的。但事实并非如此。u plz能解释一下吗?它不能在JDK1.5、1.6和1.7中编译,但可以在JDK1.8中运行 更新:它与第一个JDK8版本一起工作的事实似乎实际上是一个bug:它在JDK 1.8.0_05中工作,但根据medvedev1088的描述和回答,该代码将不再在1.8.0_25中编译,这是符合JLS的行为 我不认为这是一个已经修复的bug。相反,这是与Java8

我已经搜索过了,发现加宽优先级高于取消装箱,所以在上面的方法调用中,应该调用第一个方法,因为第二个参数对这两个方法都是相同的。但事实并非如此。u plz能解释一下吗?

它不能在JDK1.5、1.6和1.7中编译,但可以在JDK1.8中运行

更新:它与第一个JDK8版本一起工作的事实似乎实际上是一个bug:它在JDK 1.8.0_05中工作,但根据medvedev1088的描述和回答,该代码将不再在1.8.0_25中编译,这是符合JLS的行为

我不认为这是一个已经修复的bug。相反,这是与Java8中lambda表达式的方法调用机制相关的更改的结果

大多数人可能会同意,关于“方法调用表达式”的部分是Java语言规范中最复杂、最不可理解的部分。可能会有一整个工程师团队负责交叉检查和验证这一部分。因此,任何陈述或任何试图进行的推理都应该被视为是一厢情愿。(即使来自上述工程师)。但我会尝试一下,至少充实一下其他人可能参考的相关部分,以便进行进一步分析:

考虑到关于

  • 在JLS 7中
  • 在JLS 8中
考虑到这两种方法都是“潜在适用的方法”(/),那么相关小节是关于

  • 在JLS7中
  • 在JLS8中
对于JLS 7,它指出

当且仅当以下所有条件成立时,方法m才是适用的变量算术方法:

  • 对于1=i
(其他条件是指此处不相关的调用形式,例如真正使用varargs的调用,或涉及泛型的调用)

参考示例:当可以通过方法调用转换将
b
转换为相应的形式方法参数时,方法适用于类型为
Byte
的实际参数表达式
b
。根据JLS7中关于的相应章节,允许进行以下转换:

  • 身份转换(§5.1.1)
  • 扩大原语转换(§5.1.2)
  • 拓宽参考转换(§5.1.5)
  • 装箱转换(§5.1.7)后可选加宽参考转换
  • 取消装箱转换(§5.1.8)后可选地进行加宽原语转换
显然,根据本规范,有两种方法适用:

  • m(编号b,编号…a)
    通过加宽参考转换适用
  • m(字节b,数字…a)
    通过拆箱转换适用
您提到您“…发现加宽优先级高于取消装箱”,但此处不适用:上述条件不涉及任何“优先级”。它们被列为不同的选项。即使第一种方法是
void m(字节b,数字…a)
,也可以使用“标识转换”,但它仍然只计算为一种可能的转换,并且由于模糊性而导致错误方法


因此,据我所知,这就解释了为什么它不使用JDK7。我没有详细了解它为什么能与JDK8一起工作。但变量算术方法适用性的定义在以下方面发生了微小变化:

如果m不是泛型方法,那么m通过变量arity调用适用,如果,对于1≤ 我≤ k、 ei与Ti在松散调用上下文中兼容,或者ei与适用性无关(§15.12.2.2)

(我还没有深入探讨“松散调用上下文”的定义和§15.12.2.2节,但这似乎是这里的关键区别)



另一方面,再次提到您的陈述,您“…发现扩展优先级高于取消绑定”:对于不涉及varargs的方法(并且根本不需要方法调用转换),这是正确的。如果您在示例中遗漏了varags,那么查找匹配方法的过程将从中开始。由于
Byte
Number
的子类型,因此方法
m(Number b)
将已经适用于参数
Byte b
。没有理由去调查。在这个阶段,通过从
字节
字节
的解装箱将应用方法调用转换,但这个阶段从未达到。

它为我编译-您使用的是哪种编译器?(哪种版本?)这些优先顺序是以独立的步骤进行的。首先是直接,然后是加宽,然后是取消装箱。@Sotirios Delimanolis你能详细说明你的答案吗?这不能用IntelliJ编译,但可以用
javac
很好地工作。JDK 1.8版无法在上编译。似乎Java 8中已经修复了一个bug。这里有一个类似的问题@medvedev1088我仍然没有研究与“调用上下文”等相关的更新细节。但是现在,根据您链接到的问题(以及您的答案),这里的代码在早期的JDK8版本中是一个bug,这个bug在8-25版本中被修复了,你同意吗?是的,我同意。刚刚在JDK1.8.0_25上测试过,但没有编译。而且它不应该根据JLS,因为编译器无法确定哪个方法更具体。它还提出了一个重要的问题:是否应该改进JLS以及如何改进JLS。有些编译器错误是违反直觉的,例如
public class Primitive {
    void m(Number b, Number ... a) {} // widening, autoboxing->widening->varargs

    void m(byte b, Number ... a) {} // unboxing, autoboxing->widening->varargs

    public static void main(String[] args) {
        Byte b = 12;
        Primitive obj = new Primitive();
        obj.m(b, 23);
    }
}