Java 为什么这个方法重载不明确?
我已经搜索过了,发现加宽优先级高于取消装箱,所以在上面的方法调用中,应该调用第一个方法,因为第二个参数对这两个方法都是相同的。但事实并非如此。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语言规范中最复杂、最不可理解的部分。可能会有一整个工程师团队负责交叉检查和验证这一部分。因此,任何陈述或任何试图进行的推理都应该被视为是一厢情愿。(即使来自上述工程师)。但我会尝试一下,至少充实一下其他人可能参考的相关部分,以便进行进一步分析: 考虑到关于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
- 在JLS 7中
- 在JLS 8中
- 在JLS7中
- 在JLS8中
- 对于1=i
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);
}
}