我知道这个问题多次讨论过,但我还是不明白。
研究此代码:
public class Main {
public static void var(Integer x, int y) {
System.out.println("Integer int");
}
public static void var(int... x) {
System.out.println("int... x");
}
public static void var(Integer... x) {
System.out.println("Integer...");
}
public static void main(String... args) {
byte i = 0;
Integer i2 = 127;
var(i, i2);
}
}
在我的大脑遵循规则:
加宽
拳击
拳击+可变参数
根据这条规则我会做下一步行动
1.byte wides to int
现在我有int
Integer
,并且存在方法需要Integer
和int
2.make boxing
因此。 int
- > Integer
和Integer
- > int
个参数
我认为这些论点是适用的,并且预计会看到
Integer int
输出中的。
但我明白了
int ...
为什么?
答案 0 :(得分:5)
现在很明显,方法var(int...)
已被选中,而不是var(Integer...)
。
原因是只允许应用某些转化,并且它只能是列表中的转化之一,而不是转化链。 不允许java编译器首先进行扩展原语转换,然后进行装箱转换。
在Java Language Specification in section 5.3
中指定5.3。方法调用转换
方法调用转换应用于a中的每个参数值 方法或构造函数调用(§8.8.7.1,§15.9,§15.12):类型 必须将参数表达式转换为类型 相应的参数。
方法调用上下文允许使用_ _中的一个
- 身份转换(第5.1.1节)
- 扩大原始转换(第5.1.2节)
- 扩大参考转换(第5.1.5节)
- 拳击转换(§5.1.7),可选地后跟加宽引用 转化
- 取消装箱转换(第5.1.8节),可选地后跟加宽 原始转换。
编译器的唯一选择是:
将(byte, Integer)
变为(int, int)
。
首先不能将第一个参数byte
转换为int
,然后对int
到Integer
的相同参数应用装箱转换,因为顺序中的两个转换是不允许。
让我们回过头来了解编译器如何选择要调用的重载方法。这在JLS 15.12.2中有所描述。 (15.12.1描述了如何找到要搜索的类或接口,但我们已经知道我们想在类Main
中调用静态方法)
编译器选择正确重载方法的前两个阶段不适用于变量参数(“变量arity”)方法,但第三阶段确实如此:
第三阶段(§15.12.2.4)允许重载与 变量arity方法,装箱和拆箱。
第15.12.4节非常复杂,但适用的规则是:
所以......
var
(byte, Integer)
的方法
var(Integer...)
byte
转换为Integer
(方法中声明的参数类型)byte
转换为Integer
- 它不能执行两个步骤。var(Integer...)
var(int...)
byte
转换为int
。这是一个复选标记。Integer
,它看到JLS 5.3允许编译器使用拆箱转换将其转换为int
。所以这也是一个复选标记。var(int...)
是一个很好的匹配。var
的方法,因此var(int...)
是唯一适用的方法。编译器现在将生成代码以执行必要的转换并调用该方法。答案 1 :(得分:2)
Java只能做" box和wide"不是"宽和盒子"。例如,
因此,在您给定的方法中,第一个参数字节已经失败了两个Integer方法。因此,只有int ...适用。
我为demo编写了以下类:
public class Overload{
public static void primitiveWiden(int x){
System.out.println("int");
}
public static void refWiden(Map m){
System.out.println("Map");
}
public static void priWideAndBox(Integer o){//doesn't work
System.out.println("Object");
}
public static void boxAndRefWide(Number n){//it works
System.out.println("Number");
}
public static void main(String[] args){
byte b =0;
int i =0;
HashMap m = new HashMap();
primitiveWiden(b);
refWiden(m);
priWideAndBox(b);//compile error
boxAndRefWide(i);
}
}