我认为这会是一个愚蠢的问题,但我不知道为什么会这样。
代码;
public class OverloadingTest {
public static int sum(int ...a){
int sum=0;
for(int i : a){
sum += i;
}
System.out.print("this is variant args//");
return sum;
}
public static double sum(double a, double b) {
return a + b;
}
public static void main(String[] args) {
System.out.println(sum(1.5, 2.5));
System.out.println(sum(10, 20));
System.out.println(sum(10, 20,30));
}
}
我预期的结果;
4.0
this is variant args//30
this is variant args//60
控制台中的实际结果:
4.0 30.0 this is variant args//60
我无法确定为什么sum(10, 20)
30.0的结果,而不是变量参数的结果。
答案 0 :(得分:6)
这是因为编译器总是选择使用最具体的方法。
由于您的第二次调用有两个参数,并且int
可以转换为double
而不会丢失精度(请参阅JLS, section 5.1.2),编译器会选择调用您的两个参数方法
IDE会在此向您发出有关隐式int
到double
转换的警告。
编辑:正如@OlegEterkhin在评论中提到的,请参阅JLS, section 15.2.2,了解编译器用于选择将使用哪种方法的过程。
不,这不会起作用:
int x = sum(10, 20);
答案 1 :(得分:5)
答案在JLS section 15.12.2。基本上,编译器试图找到任何适用的方法,而不必扩展varargs,只有在必须使用varargs时才会:
该过程的其余部分分为三个阶段,以确保与Java SE 5.0之前的Java编程语言版本兼容。阶段是:
第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换,或使用变量arity方法调用。如果在此阶段没有找到适用的方法,则处理继续到第二阶段。 [...]
第二阶段(第15.12.2.3节)执行重载解析,同时允许装箱和拆箱,但仍然排除使用变量arity方法调用。如果在此阶段没有找到适用的方法,则处理继续到第三阶段。 [...]
第三阶段(§15.12.2.4)允许重载与变量arity方法,装箱和拆箱相结合。
在这种情况下,第一阶段会找到匹配项,因为sum(double, double)
因sum(10, 20)
到int
的隐式转换而适用于double
{{1}}。
答案 2 :(得分:1)
在行中:
System.out.println(sum(10, 20));
参数的数字与sum(double a, double b)
的签名相匹配,并且它是最准确的方法,而且它是选择的那个通过编译器。
有关详细信息,请参阅15.12.2. Compile-Time Step 2: Determine Method Signature。
答案 3 :(得分:1)
根据这篇文章Varargs in method overloading in Java
当选择要选择哪种重载方法时,当组合Boxing,Widening和Var-args时,会遵循一些规则: -
Primitive widening uses the smallest method argument possible
Wrapper type cannot be widened to another Wrapper type
You can Box from int to Integer and widen to Object but no to Long
Widening beats Boxing, Boxing beats Var-args.
You can Box and then Widen (An int can become Object via Integer)
You cannot Widen and then Box (An int cannot become Long)
You cannot combine var-args, with either widening or boxing
答案 4 :(得分:1)
类型推断具有优于varargs的优先级。由于您使用2个参数调用方法,因此在搜索varargs方法之前,它会尝试查找包含2个参数的匹配项(即使使用类型推断)(即使使用正确的类型)。
答案 5 :(得分:1)
此行为在specification中定义。 “变量arity方法,装箱和取消装箱”在方法签名解析的第三阶段处理,首先尝试匹配签名而不使用变量arity方法。