6

I faced with same code:

    public class Devk{
        public static void tMeth(Integer... i){
          System.out.print("A");
        }
        public static void tMeth(int... i){
          System.out.print("B");
        }
        public static void main(String args[]){
          tMeth(Integer.valueOf("7"));//compile error
          tMeth(new int[2]); //returns B
          tMeth(new Integer[2]); //returns A
        }

  }

after invokation I see

java: reference to tMeth is ambiguous, both method tMeth(java.lang.Integer...) in GenericsTest.Test1 and method tMeth(int...) in GenericsTest.Test1 match

method Integer.valueOf("7") returns Integer wrapper. I expect to see A in console.

Who can explain this behaviour and provide general rule for this ?

P.S.

public static void tMeth(Integer i){
    System.out.print("A");
}
public static void tMeth(int i){
    System.out.print("B");
}
public static void main(String args[]){
    tMeth(1); //returns B
    tMeth(new Integer(1)); //returns A
}
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • 2
    The general rule is don't program like this. Avoid any ambiguity. – Sotirios Delimanolis Mar 06 '14 at 19:53
  • It is question from test – gstackoverflow Mar 06 '14 at 19:54
  • Looks like you haven't done any search about this topic. At least try searching the error message from the compiler before posting the question here. – Luiggi Mendoza Mar 06 '14 at 19:55
  • I don't see clear general rule for this – gstackoverflow Mar 06 '14 at 19:57
  • 2
    @Luiggi, I think he knows what the error means. He is just asking why this occurs when the call to ValueOf returns an Interger wrapper, but doesn't happen if he passes an Integer wrapper directly. It's a valid question. – Jim Mar 06 '14 at 19:57
  • Check this answer out: http://stackoverflow.com/questions/14053596/compiler-error-reference-to-call-ambiguous – cloudwalker Mar 06 '14 at 19:58
  • @Jim read the possible duplicate Q/A and let me know if this isn't covered there (which is, in fact, case 2 stated in the question). – Luiggi Mendoza Mar 06 '14 at 19:58
  • 1
    @Luiggi, this is indeed a duplicate of the post that rpax linked to. That post answers the question exactly. However, the OP has a valid question that is appropriate for this forum, and he shouldn't be berated for not finding the answer; this isn't a basic 101 type question. – Jim Mar 06 '14 at 20:03
  • @Jim I haven't said this question is not proper for SO but it is a duplicate, which means OP could have search about this topic on the net, note that this topic [is not new](https://www.google.com/search?q=java+reference+to+method+is+ambiguous&oq=java+reference+to+met&aqs=chrome.2.69i57j0l5.5584j0j7&sourceid=chrome&espv=210&es_sm=93&ie=UTF-8). – Luiggi Mendoza Mar 06 '14 at 20:05

4 Answers4

8

When compiling a method call, the compiler searches for a matching method in this order:

  1. Try to find a method without autoboxing/unboxing or varargs.
  2. If no method is found, see if a method matches using autoboxing/unboxing.
  3. If still no method is found, see if a method matches using both varargs and autoboxing/unboxing.

In your case, you are in step (3) here. Since unboxing is allowed, both methods are applicable.

The compiler then tries to find the one that is most specific. One method is more specific than another if its parameter types are all equally or more specific (for example, String is more specific than Object, and int is more specific than long).

But between int and Integer, neither is more specific; the compiler relies on testing (1) before (2) above to get the correct method in the case of, say, foo(int) and foo(Integer).

So, there are two applicable methods and neither is more specific, hence the ambiguity error.

JLS reference

Russell Zahniser
  • 16,188
  • 39
  • 30
0

This behavior is caused by Java's auto-boxing respectively Java's auto-unboxing.

Java will automatically convert primitive types to its corresponding wrapper classes and wrapper classes to its corresponding primitive types. That makes it possible to pass an "int" to a method which requires an "Integer" or an "Integer" to a method which requires an "int". Java will automatically convert the types.

In your specific case this causes the ambiguity, since there are two potential methods available for the call.

You can read more about it here: http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

Thomas Uhrig
  • 30,811
  • 12
  • 60
  • 80
-2

Integer (and Double, Byte, Float, Long, etc.) are the wrapper classes of the primitive data types.

You can't have one method using int and another using Integer since Java 5 because of autoboxing, which will convert any int variable to its Integer counterpart (and any Integer to int, raising a NullPointerException if the object is null).

eebbesen
  • 5,070
  • 8
  • 48
  • 70
sam101
  • 1
  • 1
-2

This is because of a feature called 'Autoboxing' in java where a given primitive value will automatically be boxed into it's wrapper class. The primitive value here is int and the wrapper class is Integer. Since 7 matched both primitive value 7 and Integer value 7, both methods collide.

Since the compiler will pass a primitive value to arguments matching primitive and wrapper type (and vice versa for wrapper type), you are not really overloading methods here as much as duplicating them.

ucsunil
  • 7,378
  • 1
  • 27
  • 32
  • To have **public static void tMeth(Integer i)** and **public static void tMeth(int i)** and invoke with int or Integer is valid construction – gstackoverflow Mar 06 '14 at 20:00
  • While the compiler returns a wrapper on valueOf(), it is not smart enough to know whether you intend valueOf() to resolve to an int or a wrapper at run time. When you directly pass in a primitive or a wrapper class, the compiler knows what to expect. – ucsunil Mar 06 '14 at 20:14
  • `it is not smart enough to know whether you intend valueOf() to resolve to an int or a wrapper at run time.` Of course it is. `valueOf()` is declared to return an `Integer`. – Sotirios Delimanolis Mar 06 '14 at 20:21