Why ambiguous error when using varargs overloading with primitive type and wrapper class? [duplicate]
Asked Answered
R

2

8

I do not understand why here in case 1, it is not giving compilation error, contrary in case 2 (varargs), it gives compilation error. Can anyone please elaborate what differences the compiler makes in these two cases? I went through many posts about it, but not able to understand it yet.

Case #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);
    }
}

The Output is: 1

Case #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);
    }
}

Compilation Error:

The method display(int[]) is ambiguous for the type Test
Revolutionist answered 3/4, 2016 at 10:51 Comment(6)
Yeah, your problem comes along with AutoBoxing, as Java is not sure whether to interpret '0' as an int or an Integer...Wehner
@JayC667, is the same problem not in the case 1? I mean why in case 1 java is sure to call public void display(int a)? How? why only in case 2 it went unsure?Revolutionist
My best guess would be that due to Java's AutoBoxing feature, varargs/paramarrays have to be considered for AutoBoxing conversions by the compiler, too. So the compiler will offer two conversions, to put parameters into an array: 1) directly, passing primitive types, passing new int[] {0}, thus matching display(int... a), 2) via AutoBoxing for the vararg params, converting your 0 to new Integer[] {0}, matching your display(Integer... a) method.Wehner
Now with those two offers, the compiler cannot find one method signature that matches better than the other, thus throwing its undecisiveness back at you, welcoming you to add a dummy parameter or explicitly casting your params into an arrayWehner
@AR.3, Do not mark it duplicate. The one you have specified is different one. Here I have asked for differences between two cases which is no where in that question which you marked it as duplicate of.Revolutionist
@Revolutionist The answers to the duplicate explain the difference between the two cases.Huzzah
L
6

In your first example the display(int) method is invoked in strict invocation context while display(Integer) is invoked in loose invocation context (since auto-boxing is required). Thus the compiler chooses the display(int) method according to JLS. Invocation contexts are explained here JLS 5.3. Invocation Contexts

In the second example both methods are invoked in loose invocation context thus the compiler needs to find the most specific method JLS 15.12.2.5 Choosing the Most Specific Method. Since int is not a subtype of Integer there is no most specific method and the compiler throws a compilation error.

You can find my explanation for a similar compilation error here Method overload ambiguity with Java 8 ternary conditional and unboxed primitives

The parts that apply to this case:

Identifying applicable methods is divided into 3 phases.

The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.

The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.

The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.

For the first example only the display(int) method is matched on the first phase thus it is chosen. For the second example both methods are matched on the 3rd phase thus the Choosing the Most Specific Method algorithm comes into play JLS 15.12.2.5 Choosing the Most Specific Method:

m2 is not generic, and m1 and m2 are applicable by variable arity invocation, and where the first k variable arity parameter types of m1 are S1, ..., Sk and the first k variable arity parameter types of m2 are T1, ..., Tk, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ k). Additionally, if m2 has k+1 parameters, then the k+1'th variable arity parameter type of m1 is a subtype of the k+1'th variable arity parameter type of m2.

As mentioned earlier there is no most specific method since int <: Integer does not satisfy.

Lenis answered 3/4, 2016 at 11:3 Comment(0)
H
-1

After java Version 1.5 there is a cool feature introduced named autoboxing which enables compiler to Convert a primitive type to a Wrapper Type. So, during compilation both method will be work same.

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

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

both the function will be treated as a same method because of autoboxing performs during the compilation . So Be Beware of Autoboxing while overloading method in Java.

More you find Here..

Best Practices Of Method Overloading

Haemorrhage answered 3/4, 2016 at 11:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.