Why do two methods with signature (primitive, wrapper) and (primitive, primitive) cause the method call (wrapper, primitive) to be ambiguous?

StackOverflow https://stackoverflow.com/questions/20923888

  •  24-09-2022
  •  | 
  •  

Question

It's just an exercise but I can't figure out the ambiguity:

private static void flipFlop(String str, int i, Integer iRef) {
System.out.println(str + "ciao");
}

private static void flipFlop(String str, int i, int j) {
System.out.println(str + "hello");
}

public static void main(String[] args) {
flipFlop("hello", new Integer(4), 2004);
}

It says:

The method flipFlop(String, int, Integer) is ambiguous for the type Test

I would have guessed that the second argument would have been unwrapped to int and so the second flipFlop method would have been the choice.

Was it helpful?

Solution

If you enjoy riveting reading, here is the relevant portion of the Java Language specification that describes how methods are resolved.

But basically your third argument can be interpreted as a primitive or an autoboxed wrapper, and the compiler can't figure out what you want. Both methods are "maximally specific" to use the JLS terminology.

OTHER TIPS

Alright, I have taken a closer look at the JLS and I believe this should clear up any remaining doubts you might have.

This is the original problem:

public class Main {
    private static void flipFlop(int i, Integer iRef) {
        System.out.println("Method 1");
    }

    private static void flipFlop(int i, int j) {
        System.out.println("Method 2");
    }

    public static void main(String[] args) {
        flipFlop(new Integer(4), 2004);
    }
}

As has been pointed out in the other answer: this fails because the compiler can't decide what overload to use.

However you might think this doesn't make any sense. The compiler can decide just fine in this situation what method he should use:

public class Main {
    private static void flipFlop(Integer y) {
        System.out.println("ciao");
    }

    private static void flipFlop(int j) {
        System.out.println("hello");
    }

    public static void main(String[] args) {
        flipFlop(new Integer(6));
        flipFlop(6);
    }
}

Rationality tells us that when you have values X + Y and two methods that take respectively Y + X and Y + Y and you know that X and Y are interchangeable, then this would mean that the latter method is more specific.

The difference between these two are described in the JLS. I have provided the entire workflow below, but what matters is this:

First the compiler will look at methods with an equal signature while forbidding boxing/unboxing. In our second example this doesn't cause any problems, but in our first example this doesn't return a satisfiable method since neither of them take an Integer as the first parameter..

When that failed, the compiler moves on to the second step where it allows boxing/unboxing. This should fix the issue we had with the first parameter, but now causes ambiguity with the second parameter since it is now uncertain whether you're referring to the overload using an int or the one using an Integer.

This ultimately results in an ambiguous method call.

15.12.2. Compile-Time Step 2: Determine Method Signature

  1. 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.

  2. 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.

If several applicable methods have been identified during one of the three phases of applicability testing, then the most specific one is chosen, as specified in section §15.12.2.5.

15.12.2.5. Choosing the Most Specific Method

A method is said to be maximally specific for a method invocation if it is accessible and applicable and there is no other method that is applicable and accessible that is strictly more specific.

It is possible that no method is the most specific, because there are two or more methods that are maximally specific. In this case:

  • If all the maximally specific methods have override-equivalent (§8.4.2) signatures, then: (... some rules to decide who's chosen ...)

  • Otherwise, we say that the method invocation is ambiguous, and a compile-time error occurs.

Your second argument 2004 which is an int would also apply to an Integer because of auto-boxing, thats why the compiler can't decide which method to use.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top