使用原始类型和包装类的varargs重载时为什么会出现模糊错误?

时间:2016-04-03 10:51:04

标签: java overloading wrapper variadic-functions primitive

我不明白为什么在这里的情况1,它没有给出编译错误,相反在情况2(varargs),它给出了编译错误。任何人都可以详细说明编译器在这两种情况下的差异吗?我经历过很多关于它的帖子,但还不能理解它。

案例#1

public class Test {

    public void display(int a) {
        System.out.println("1");
    }

    public void display(Integer a) {
        System.out.println("2");
    }

    public static void main(String[] args) {
        new Test().display(0);
    }
}

输出为: 1

案例#2

public class Test {

    public void display(int... a) {
        System.out.println("1");
    }

    public void display(Integer... a) {
        System.out.println("2");
    }

    public static void main(String[] args) {
        new Test().display(0);
    }
}

编译错误

The method display(int[]) is ambiguous for the type Test

2 个答案:

答案 0 :(得分:5)

在第一个示例中,在严格的调用上下文中调用display(int)方法,而在松散的调用上下文中调用display(Integer)(因为需要自动装箱)。因此编译器根据JLS选择display(int)方法。调用上下文在此处解释JLS 5.3. Invocation Contexts

在第二个示例中,在松散调用上下文中调用这两个方法,因此编译器需要找到最具体的方法JLS 15.12.2.5 Choosing the Most Specific Method。由于int不是Integer的子类型,因此没有最具体的方法,编译器会抛出编译错误。

您可以在Method overload ambiguity with Java 8 ternary conditional and unboxed primitives

找到类似编译错误的解释

适用于此案例的部分:

  

确定适用的方法分为3个阶段。

     

第一阶段(§15.12.2.2)在没有的情况下执行重载决策   允许装箱或拆箱转换,或使用变量   arity方法调用。如果没有找到适用的方法   这个阶段然后处理继续到第二阶段。

     

第二阶段(§15.12.2.3)执行重载解析   允许装箱和拆箱,但仍然排除使用   变量arity方法调用。如果没有找到适用的方法   在这个阶段,然后处理继续到第三阶段。

     

第三阶段(§15.12.2.4)允许重载与   变量arity方法,装箱和拆箱。

对于第一个示例,只有display(int)方法在第一个阶段匹配,因此选择它。对于第二个示例,两个方法在第三阶段匹配,因此选择最具体方法算法发挥作用JLS 15.12.2.5 Choosing the Most Specific Method

  

m2不是通用的,m1和m2适用于变量arity   调用,以及m1的第一个k变量arity参数类型   是S1,...,Sk和m2的第一个k变量arity参数类型   是T1,...,Tk,Si的类型比参数ei的Ti更具体   对于所有i(1≤i≤k)。另外,如果m2有k + 1个参数,那么   m1的第k + 1个可变arity参数类型是该类型的子类型   k + 1的可变参数类型m2。

如前所述,由于int&lt ;: Integer不满足,因此没有最具体的方法。

答案 1 :(得分:-1)

在Java Version 1.5之后,引入了一个名为autoboxing的酷炫功能,它使编译器能够将原始类型转换为 Wrapper Type 。因此,在编译期间,这两种方法都是一样的。

    public void display(int... a) {
        System.out.println("1");
    }

    public void display(Integer... a) {
        System.out.println("2");
    }

由于autoboxing编译期间执行,因此该函数将被视为同一方法。所以在Java中重载方法时要小心 Autoboxing

你在这里找到的更多......

Best Practices Of Method Overloading