下面的代码无法编译。
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.
}
}
发出编译时错误。
参照测试是不明确的,在varargspkg.Main匹配在两个varargspkg.Main方法测试(INT ...)和方法试验(浮动...)
这似乎是因为很明显在该方法调用中的参数值test(1, 2);
可以晋升到int
以及float
如果这些参数中的任何一个或两个由后缀F
或f
,它编译。
如果我们然而,表示与相应的包装类型的方法中的签名接收参数如下
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
可变参数参数(第一个在前面的片段)。
为什么在这种情况下,误差在第一种情况不报? 看来,自动装箱和自动型的推广都在这里应用。 首次应用于自动装箱,这样的错误得到解决?
甲骨文的文档说,
一般来说,你不应该重载可变参数的方法,或将难以程序员找出哪些超载被调用。
在这最后一句链接 。 它然而,对于更好地理解可变参数的缘故。
还添加以下代码编译就好了。
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");
}
}
编辑:
以下是快照指示编译错误。 我创建了一个新的应用程序,因此包名是不同的。
我使用的是JDK 6。
您可以Widen
或Box
,但你不能两者都做,除非你是boxing and widening
到Object
(一个int,整数(拳击),然后整数到对象(扩大)是合法的,因为每个类的子类Object
,所以它是可能的Integer
要传递给Object
参数)
同样的int
以Number
也是合法的(INT - >整数- >号)由于编号是父类的Integer
这是可能的。
让我们来看看在你的榜样: -
public static void test(Integer...i)
public static void test(Float...f)
有选择其中重载方法来选择,当拳击,加宽,和VAR-ARGS结合时所遵循的一些规则: -
- 原始拓宽使用
smallest
方法参数可能 - 包装类型不能被加宽到另一个包装类型
- 您可以从int到整数框,并扩大到对象,但没有龙
- 拓宽节拍拳击,拳击击败VAR-ARGS。
- 您可以框,然后拓宽(一个
int
可以成为Object
通过Integer
) - 你不能拓宽,然后盒(一个
int
不能成为Long
) - 不能合并VAR-ARGS,有或者是扩大或者拳击
因此,基于上面给出的规则: -
当你传递两个整数上述功能,
- 根据规则3,它必须首先被
Widened
,然后Boxed
适应一个Long
,根据规则5(你不能拓宽然后箱),这是非法的。 - 因此,它是盒装在存储
Integer
VAR-ARGS。
但是,在第一种情况下,你有方法var-args
基本类型: -
public static void test(int...i)
public static void test(float...f)
然后test(1, 2)
可以调用这两种方法(因为它们都不是更适合于rule 1
适用): -
- 在第一种情况下这将是
var-args
- 在第二种情况下,将被加宽,然后VAR-ARGS(其是允许的)
现在,当你有一个准确int和一个flost方法: -
public static void test(int i)
public static void test(float f)
然后使用调用test(1)
规则1之后,与最小的可能的加宽(即, int
被选择其中需要完全没有加宽)。 所以,第一个方法将被调用。
欲了解更多信息,可以参考JLS - Method Invocation Conversion
在Java中, 1
是你如何代表int
。 它可以是自动装箱为实例Integer
或晋升为float
,而这也解释了为什么编译器不能对应该调用的方法决定。 但它永远不会被自动装箱为Long
或Float
(或任何其他类型)。
在另一方面,如果你写1F
,它是一种的表现float
,即可以自动装箱为一个Float
(和,本着同样的精神,将永远不会自动装箱到一个Integer
或其他任何东西)。
为什么在这种情况下,误差在第一种情况不报? 看来,自动装箱和自动型的推广都在这里应用。 应用于自动装箱第一错误得到解决?
只是一个意见 - 在可变参数的情况下,JVM实际上已经创建的参数数组。 在整数和浮点数的情况下,很明显应该建立什么类型的数组。 因此,它可能会是毫不含糊错误的原因。
但尽管如此,它是一种混乱的,为什么不能创建一个整数数组,时默认1,3是整数。
看起来这已经在过去这里讨论的SO 可变参数和重载的错误? 并且是INFACT 一个错误 ,根据讨论。
在Java 6中,问题出在时间instantiation
的仿制药的发现这方法可调用之前。
When you write 1,2
-> it can be be both int[] or float[] and hence the issue being complained.
When you write 1,2F
-> it can be be only float[] and hence the NO issue being complained.
同样的,另外两个选项,也就是
When you write 1F,2
-> it can be be only float[] and hence the NO issue being complained.
When you write 1F,2F
-> it can be be only float[] and hence the NO issue being complained.
在另一方面,当您使用int
或float
,不存在变量类型实例。 当您使用1
,则会试图寻找方法与int
作为参数,第一个,如果不是,它促进的类型和标识与浮动方法。 如果这两种方法可供选择,分别与int
将首先使用。
歧义的问题不会再在Java 7中 ,因为它具有更好的操控性数据类型检查和推广。