Compiler error : reference to call ambiguous

19,346

Solution 1

Finding the most specific method is defined in a very formal way in the Java Language Specificaion (JLS). I have extracted below the main items that apply while trying to remove the formal formulae as much as possible.

In summary the main items that apply to your questions are:

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

  • Then JLS 15.12.2.4 basically determines that both method are applicable, because 10 can be converted to both an Integer... or an int.... So far so good. And the paragraph concludes:

The most specific method (§15.12.2.5) is chosen among the applicable variable-arity methods.

  • Which brings us to JLS 15.12.2.5. This paragraph gives the conditions under which an arity method m(a...) is more specific than another arity method m(b...). In your use case with one parameter and no generics, it boils down to:

m(a...) is more specific than m(b...) iif a <: b, where <: means is a subtype of.

It happens that int is not a subtype of Integer and Integer is not a subtype of int.

To use the JLS language, both call methods are therefore maximally specific (no method is more specific than the other). In this case, the same paragraph concludes:

  • If all the maximally specific methods have override-equivalent (§8.4.2) signatures [...] => not your case as no generics are involved and Integer and int are different parameters
  • Otherwise, we say that the method invocation is ambiguous, and a compile-time error occurs.

NOTE

If you replaced Integer... by long... for example, you would have int <: long and the most specific method would be call(int...)*.
Similarly, if you replaced int... by Number..., the call(Integer...) method would be the most specific.

*There was actually a bug in JDKs prior to Java 7 that would show an ambiguous call in that situation.

Solution 2

Looks like it's related to bug #6886431, which seems to be fixed in OpenJDK 7.

Below is the bug description,

Bug Description:

When invoking a method with the following overloaded signatures, I expect an ambiguity error (assuming the arguments are compatible with both):

int f(Object... args);
int f(int... args);

javac treats the second as more specific than the first. This behavior is sensible (I prefer it), but is inconsistent with the JLS (15.12.2).

Solution 3

from JLS 15.12.2.2

JLS 15.12.2.2 Choose the Most Specific Method

IIf more than one method declaration is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen. The informal intuition is that one method declaration is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.

neither of these methods can be passed to the other (the types for int[] and Integer[] arent related) hence the call is ambiguous

Solution 4

The compiler doesn't know which method should be called. In order to fix this, you need to cast the input parameters..

public static void main(String... args) {
  call((int)10);
  call(new Integer(10));
}

EDIT:

It is because the compiler tries to convert the Integer into int, Therefore, an implicit cast takes place prior to invocation of the call method. So the compiler then looks for any methods by that name that can take ints. And you have 2 of them, so the compiler doesn't know which of both should be called.

Share:
19,346

Related videos on Youtube

Ravi
Author by

Ravi

Check-out my open source library : rabbitFT : It is a library for sharing file through SFTP or Sharepoint channel.

Updated on October 09, 2022

Comments

  • Ravi
    Ravi over 1 year

    Case 1

    static void call(Integer i) {
        System.out.println("hi" + i);
    }
    
    static void call(int i) {
        System.out.println("hello" + i);
    }
    
    public static void main(String... args) {
        call(10);
    }
    

    Output of Case 1 : hello10

    Case 2

    static void call(Integer... i) {
        System.out.println("hi" + i);
    }
    
    static void call(int... i) {
        System.out.println("hello" + i);
    }
    
    public static void main(String... args) {
        call(10);
    }
    

    Shows compilation error reference to call ambiguous. But, I was unable to understand. Why ? But, when I commented out any of the call() methods from Case 2, then It works fine. Can anyone help me to understand, what is happening here ?

  • Ravi
    Ravi over 11 years
    you just told the solution. My question was why ?? why it is not working ?? Any reference ?
  • Ravi
    Ravi over 11 years
    Which means, its bug of java ??
  • Jayamohan
    Jayamohan over 11 years
    Which version of Java you are using. If possible provide your eclipse version too.
  • radai
    radai over 11 years
    the bug you mentioed makes things compile when they shouldnt. this isnt it.
  • Jayamohan
    Jayamohan over 11 years
    Please don't guess your versions. Be specific. I requested your eclipse version too(If you are using Eclipse).
  • Ravi
    Ravi over 11 years
    Its jdk7, i just guess, because, i didn't remember exact version. I mean, JDK 1.7.0_19
  • assylias
    assylias over 11 years
    Although this is related, it is because the bug has been fixed that the call is ambiguous. So this does not really answer the question.
  • assylias
    assylias over 11 years
    how about double[] and int[]: these aren't related either but replacing Integer by double would remove the compile error (in JDK 7+).
  • assylias
    assylias over 11 years
    You make a confusion: S1 is int, not int[].
  • mishadoff
    mishadoff over 11 years
    @assylias S1 one of the method parameters, method have just one parameter int[]
  • assylias
    assylias over 11 years
    Si is defined as Si = Ui and U is defined as U1, ..., Uk-1, Uk[] => Uk[] <=> int[] => Uk <=> int. If it were not the case, m(Number...) would not be more specific than m(Object...) for example, because (following your reasoning) Number[] is not a subtype of Object[].
  • bacar
    bacar about 10 years
    It's worth remarking that the reason case 1 is not considered ambiguous is also described in JLS §15.12.2: "This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing." Before Java 5, there was no implicit boxing, and call(Integer i) would not be considered, hence no ambiguity.
  • Mohsen Kashi
    Mohsen Kashi over 9 years
    This problem exists in JDK8u20