用加宽和拳击重载

时间:2011-02-07 12:59:47

标签: java overloading

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

2 个答案:

答案 0 :(得分:4)

Java编译器尝试三次尝试选择适当的方法重载(JLS §15.12.2.1):

  • 阶段1:确定子类型适用的匹配Arity方法
    (可能的拳击转换和使用varargs的方法被忽略)

  • 阶段2:确定方法适用的匹配Arity方法 调用转换
    (在帐户中进行装箱转换,但忽略使用varargs的方法)

  • 阶段3:确定适用的变量Arity方法
    (检查所有可能性)

因此,使用您的示例,它的工作方式如下:

  • 没有varargs:add(long x)被确定为第一阶段唯一适用的方法(此方法适用于子类型,因为intlong的子类型,{{ 3}}),以便不执行以下阶段。

  • 使用varargs:重载解析算法进入第3阶段,其中两种方法都被识别为适用,编译器无法选择最具体的方法(选择最具体的方法是另一种复杂的算法),因此它报告含糊不清。

另见:

答案 1 :(得分:2)

因为含糊不清

2可以是Integer以及long,也可以解决这两个问题。你让编译器混淆了谁调用:)


5.12.2.2选择最具体的方法

  

如果有多个方法声明   既可访问又适用于   方法调用,有必要   选择一个来提供描述符   用于运行时方法调度。该   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)");
}

然后它会比其他两个更具体,并且方法调用将不再含糊不清。