public void add(long... x){}
public void add(Integer... x){}
add(2);
这会产生错误...为什么不对拓宽和装箱进行重叠?
但没有vararg的重载工作正常
public void add(long x){}
public void add(Integer x){}
add(2);
这里添加(长x)将被执行,这是扩大节拍拳击...为什么不相同的概念 var arguments
答案 0 :(得分:4)
Java编译器尝试三次尝试选择适当的方法重载(JLS §15.12.2.1):
阶段1:确定子类型适用的匹配Arity方法
(可能的拳击转换和使用varargs的方法被忽略)
阶段2:确定方法适用的匹配Arity方法
调用转换
(在帐户中进行装箱转换,但忽略使用varargs的方法)
阶段3:确定适用的变量Arity方法
(检查所有可能性)
因此,使用您的示例,它的工作方式如下:
没有varargs:add(long x)
被确定为第一阶段唯一适用的方法(此方法适用于子类型,因为int
是long
的子类型,{{ 3}}),以便不执行以下阶段。
使用varargs:重载解析算法进入第3阶段,其中两种方法都被识别为适用,编译器无法选择最具体的方法(选择最具体的方法是另一种复杂的算法),因此它报告含糊不清。
另见:
答案 1 :(得分:2)
因为含糊不清。
2
可以是Integer
以及long
,也可以解决这两个问题。你让编译器混淆了谁调用:)
如果有多个方法声明 既可访问又适用于 方法调用,有必要 选择一个来提供描述符 用于运行时方法调度。该 Java编程语言使用 规则,最具体的方法是 选择。非正式的直觉就是这样 一个方法声明更多 具体比另一个如果有的话 由第一种方法处理的调用 可以传递到另一个 没有编译时类型错误。
精确定义如下。 让我成为一个名字并假设那里 是名为的两个方法声明 m,每个都有n个参数。假设 一个声明出现在一个 类或接口T和那个 参数的类型是T1 ,. 。 。 ,Tn;另外假设另一个 声明出现在一个类或 接口U和那个类型 参数是U1 ,. 。 。 ,联合国然后 在T中声明的方法m更多 特定于m中声明的方法 U当且仅当以下两者兼而有之 是的:
T可以通过方法转换为U. 调用转换。 Tj可以 通过方法调用转换为Uj 转换,对于从1到n的所有j。一个 方法被认为是最大的 特定于方法调用,如果它 在那里是适用和可访问的 没有其他适用和可访问 方法更具体。如果有 是一个最具体的 方法,然后它实际上是最多的 具体方法;这是必然的 比任何其他方法更具体 这是适用和可访问的。它 然后进一步 编译时检查,如中所述 §15.12.3。
可能没有方法 最具体的,因为有两个 或更多最具体的方法。在 这种情况:
如果所有最大限度的具体方法 具有相同的签名,然后:如果一个 最具体的方法是 没有宣布抽象,它是最多的 具体方法。否则,全部 最具体的方法是 必须宣布抽象。该 选择最具体的方法 任意地最大化 具体方法。但是,最多 具体方法被认为是抛出 当且仅当是 该异常在。中声明 抛出每个的条款 最具体的方法。除此以外, 我们说方法调用是 模棱两可,编译错误 发生。
15.12.2.3示例:重载歧义
Consider the example:
class Point { int x, y; }
class ColoredPoint extends Point { int color; }
class Test {
static void test(ColoredPoint p, Point q) {
System.out.println("(ColoredPoint, Point)");
}
static void test(Point p, ColoredPoint q) {
System.out.println("(Point, ColoredPoint)");
}
public static void main(String[] args) {
ColoredPoint cp = new ColoredPoint();
test(cp, cp); // compile-time error
}
}
此示例在编译时生成错误。问题是有两个适用且可访问的测试声明,并且两者都没有比另一个更具体。因此,方法调用是不明确的。 如果添加了第三个测试定义:
static void test(ColoredPoint p, ColoredPoint q) {
System.out.println("(ColoredPoint, ColoredPoint)");
}
然后它会比其他两个更具体,并且方法调用将不再含糊不清。