案例1
static void call(Integer i) {
System.out.println("hi" + i);
}
static void call(int i) {
System.out.println("hello" + i);
}
public static void main(String... args) {
call(10);
}
案例1的输出:hello10
案例2
static void call(Integer... i) {
System.out.println("hi" + i);
}
static void call(int... i) {
System.out.println("hello" + i);
}
public static void main(String... args) {
call(10);
}
显示编译错误reference to call ambiguous
。但是,我无法理解。为什么?但是,当我从call()
注释掉任何Case 2
方法时,它的工作正常。任何人都可以帮助我理解,这里发生了什么?
答案 0 :(得分:14)
在Java语言规范(JLS)中以非常正式的方式定义了最具体的方法。我尝试尽可能地删除正式公式时,在下面提取了适用的主要项目。
总之,适用于您的问题的主要项目是:
第三阶段(§15.12.2.4)允许重载与变量arity方法,装箱和拆箱相结合。
Integer...
或int...
。到现在为止还挺好。该段的结论是:在适用的变量方法中选择最具体的方法(第15.12.2.5节)。
m(a...)
比另一种方法m(b...)
更具体的条件。在具有一个参数且没有泛型的用例中,它归结为:
m(a...)
比m(b...)
iifa <: b
更具体,其中<:
表示is a subtype of
。
恰好int
不是Integer
的子类型而Integer
不是int
的子类型。
要使用JLS语言,因此两种call
方法都是最具体的(没有方法比另一种方法更具体)。在这种情况下,同一段落结束:
- 如果所有最大特定方法都具有覆盖等效(§8.4.2)签名[...] =&gt;不是你的情况,因为没有涉及泛型,Integer和int是不同的参数
- 否则,我们说方法调用不明确,并且发生编译时错误。
注意强>
例如,如果您将Integer...
替换为long...
,则会int <: long
,而最具体的方法是call(int...)
*。
同样,如果您将int...
替换为Number...
,则call(Integer...)
方法将是最具体的。
*实际上有a bug in JDKs prior to Java 7 that would show an ambiguous call in that situation。
答案 1 :(得分:4)
看起来它与bug #6886431有关,似乎在OpenJDK 7中修复了。
以下是错误说明,
错误说明:
当调用具有以下重载签名的方法时,我 期望模糊错误(假设参数与...兼容) 两者):
int f(Object... args);
int f(int... args);
javac将第二个视为比第一个更具体。这个 行为是明智的(我更喜欢),但与JLS不一致 (15.12.2)。
答案 2 :(得分:2)
JLS 15.12.2.2选择最具体的方法
IIf多个方法声明既可访问又适用 要进行方法调用,有必要选择一个来提供 运行时方法调度的描述符。 Java编程 language使用选择最具体方法的规则。该 非正式的直觉是一种方法声明更具体 如果第一种方法处理的任何调用都可以,那么 传递给另一个没有编译时类型错误。
这些方法都不能传递给另一个(int []和Integer []的类型不相关)因此调用不明确
答案 3 :(得分:1)
编译器不知道应该调用哪个方法。为了解决这个问题,您需要转换输入参数..
public static void main(String... args) {
call((int)10);
call(new Integer(10));
}
编辑:
这是因为编译器尝试将Integer转换为int,因此,在调用call
方法之前会发生隐式转换。因此编译器然后按该名称查找可以采用整数的任何方法。你有2个,所以编译器不知道应该调用哪两个。
答案 4 :(得分:0)
如果可以应用多种方法,那么15.12.2.5
:
一个名为m
的变量arity成员方法比另一个变量arity成员方法(<: means subtyping
)更具体:
虽然原始int
已自动装箱到包装Integer
,但int[]
未自动装箱到Integer[]
,而不是第一个条件不能保留。
第二个条件几乎相同。
还有其他条件不成立,然后由于JLS:
我们说方法调用是不明确的,并且发生编译时错误。
答案 5 :(得分:0)
这个问题has already been asked多次。棘手的部分是f(1, 2, 3)
显然正在传递int
,所以为什么编译器不能选择f(int...)
版本?答案必须在JLS的某处,我正在摸不着头脑。
根据§15.12.2.4,两种方法都是适用的变量方法,因此下一步是确定最具体的方法。
不幸的是,§15.12.2.5使用 f1之间的子类型测试 T i &lt;:S i (T < sub> 1 ,.. T n )和 f2(S 1 ,.. S n )用于标识目标方法的形式参数,并且由于Integer
和int
之间没有子类型关系,因此没有人获胜,因为 int:&gt;整数或整数:&gt; INT 。在该段末尾陈述:
以上条件是一种方法的唯一情况 可能比另一个更具体。 [...]
方法m1 严格更具体,而不是另一种方法m2,如果 并且只有当m1比m2更具特异性且m2不再具体时 比m1。
对于方法调用,方法被称为最大特定 如果它是可访问和适用的,并且没有其他方法 是适用的,可访问的,严格更具体。
可能没有方法是最具体的,因为有 两种或多种最具体的方法。在这种情况下:
[...]
- 醇>
否则,我们说方法调用不明确,并且发生编译时错误。
Gilad Bracha附上a blog post(见图2),反过来联系@ Jayamhona答案的错误报告。