Java中方法重载的Varargs [英] Varargs in method overloading in Java
问题描述
以下代码无法编译。
package varargspkg;
公共类Main {
public static void test(int ... i){
for(int t = 0; t< i.length; t ++){
System.out.println(i [t]);
}
System.out.println(int);
}
public static void test(float ... f){
for(int t = 0; t< f.length; t ++){
的System.out.println(F [T]);
}
System.out.println(float);
}
public static void main(String [] args){
test(1,2); //编译错误引用如下。
}
}
发出编译时错误。
对test的引用不明确,
varargspkg.Main中的方法test(int ...)和方法测试(float ... )in varargspkg.Main match
这似乎是显而易见的,因为方法中的参数值调用 test( 1,2);
可以提升为 int
以及 float
如果任何一个或两个参数后缀为 F
或 f
,它编译。</ p>
但是,如果我们使用相应的包装类型表示方法签名中的接收参数,如下所示
public static void test(Integer ... i){
System.out.println(Integer+ Arrays .asList(I));
}
public static void test(Float ... f){
System.out.println(Float+ Arrays.asList(f));
}
然后调用方法 test(1, 2);
不会发出任何编译错误。在这种情况下要调用的方法是接受一个 Integer
varargs参数(前面代码片段中的第一个)的方法。
在这种情况下,为什么在第一种情况下没有报告错误?这里似乎都应用了自动装箱和自动类型提升。是否先应用自动装箱以便解决错误?
Oracle文档说,
一般来说,你不应该重载varargs方法,否则
将很难让程序员弄清楚哪些重载被
调用。
此
我正在使用JDK 6.
你可以加宽
或 Box
但你不能同时做到这两点,除非你装箱和加宽
到 Object
(一个int到Integer(Boxing)然后是Integer到Object(Widening)是合法的,因为每个类都是 Object
的子类,所以可以将 Integer
传递给 Object
参数)
类似地, int
到 Number
也是合法的(int - > Integer - > Number)
由于Number是 Integer的超类
,因此可以。
让我们在你的例子中看到这一点: -
publ ic static void test(Integer ... i)
public static void test(Float ... f)
选择要选择的重载方法时,遵循一些规则,当组合Boxing,Widening和Var-args时: -
- 原始扩展使用
最小
方法参数 - 包装类型无法扩展到另一种包装类型
- 你可以从int到整数并加宽到对象但不到长
- 加宽节拍拳击,拳击节拍Var-args。
- 你可以Box然后加宽(一个
int
可以通过<$ c变成对象
$ c>整数) - 你不能加宽然后Box(一个
int
不能变成长
) - 你不能将var-args与加宽或装箱结合起来
因此,基于以上给定的规则: -
当您将两个整数传递给上述函数时,
- 根据规则3,它必须是第一个
加宽
然后
装箱
以装入Long
,根据规则5(你是非法的)不能加宽,然后Box)。 - 因此,它被装箱以存储在
整数
var-args。
但在第一种情况下,你有基元类型 var-args
的方法: -
public static void test(int ... i)
public static void test(float ... f)
然后 test(1,2)
可以调用两者方法(因为它们都不适合规则1
申请): -
- 在第一种情况下,它将是
var-args
- 在第二种情况下,它将是加宽,然后是Var-args(这是允许的)
现在,当你的方法只有一个int和一个flost: -
public s tatic void test(int i)
public static void test(float f)
然后开启使用 test(1)
调用,遵循规则1,并尽可能小地扩展(即选择 int
,其中根本不需要加宽)。因此将调用第一个方法。
有关更多信息,请参阅 JLS - 方法调用转换
The following code doesn't compile.
package varargspkg;
public class Main {
public static void test(int... i) {
for (int t = 0; t < i.length; t++) {
System.out.println(i[t]);
}
System.out.println("int");
}
public static void test(float... f) {
for (int t = 0; t < f.length; t++) {
System.out.println(f[t]);
}
System.out.println("float");
}
public static void main(String[] args) {
test(1, 2); //Compilation error here quoted as follows.
}
}
A compile-time error is issued.
reference to test is ambiguous, both method test(int...) in varargspkg.Main and method test(float...) in varargspkg.Main match
It seems to be obvious because the parameter values in the method call test(1, 2);
can be promoted to int
as well as float
If anyone or both of the parameters are suffixed by F
or f
, it compiles.
If we however, represent the receiving parameters in the method signature with respective wrapper types as follows
public static void test(Integer... i) {
System.out.println("Integer" + Arrays.asList(i));
}
public static void test(Float... f) {
System.out.println("Float" + Arrays.asList(f));
}
then the call to the method test(1, 2);
doesn't issue any compilation error. The method to be invoked in this case is the one that accepts one Integer
varargs parameter (the first one in the preceding snippet).
Why is in this case the error as in the first case not reported? It appears that auto-boxing and automatic type promotion are both applied here. Is auto-boxing applied first so that the error is resolved?
The Oracle docs says,
Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called.
The last sentence in this link. It's however for the sake of better understanding varargs.
Also to add below code compiles just fine.
public class OverLoading {
public static void main(String[] args) {
load(1);
}
public static void load(int i) {
System.out.println("int");
}
public static void load(float i) {
System.out.println("float");
}
}
EDIT:
The following is the snap shot that indicates the compilation error. I have created a new application therefore the package name is different.
I'm using JDK 6.
You can either Widen
or Box
but you cannot do both, unless you are boxing and widening
to Object
(An int to Integer(Boxing) and then Integer to Object(Widening) is legal, since every class is a subclass of Object
, so it is possible for Integer
to be passed to Object
parameter)
Similarly an int
to Number
is also legal (int -> Integer -> Number)
Since Number is the super class of Integer
it is possible.
Let's see this in your example: -
public static void test(Integer...i)
public static void test(Float...f)
There are some rules that are followed when selecting which overloaded method to select, when Boxing, Widening, and Var-args are combined: -
- 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 becomeObject
viaInteger
) - You cannot Widen and then Box (An
int
cannot becomeLong
) - You cannot combine var-args, with either widening or boxing
So, based on the above given rules: -
When you pass two integers to above functions,
- according to rule 3, it will have to be first
Widened
and thenBoxed
to fit into aLong
, which is illegal according to rule 5 (You cannot Widen and then Box). - So, it is Boxed to store in
Integer
var-args.
But in first case, where you have methods with var-args
of primitive types: -
public static void test(int...i)
public static void test(float...f)
Then test(1, 2)
can invoke both the methods (Since neither of them is more suitable for rule 1
to apply) : -
- In first case it will be
var-args
- In second case, it will be Widening and then Var-args (which is allowed)
Now, when you have methods with exactly one int and one flost: -
public static void test(int i)
public static void test(float f)
Then on invoking using test(1)
, rule 1 is followed, and smallest possible widening (i.e. the int
where no widening is needed at all) is chosen. So 1st method will be invoked.
For more information, you can refer to JLS - Method Invocation Conversion
这篇关于Java中方法重载的Varargs的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!