1

So, today I've been testing Java's overloading techniques and I've come across ambiguity which I can't explain. Basically, when there is a vararg method with primitive and its corresponding wrapper the compiler complains and can't decide which one to choose and I don't understand why? It's easy for human to decide and not for compiler?

Here is the fragment which works for non-vararg parameters:

public static void main(String[] args)
{
    int a = 14;
    Integer b = new Integer(14);
    stuff(a);
    stuff(b);
}

static void stuff(Integer arg) { System.out.println("Integer"); }
static void stuff(int arg) { System.out.println("int"); }

And here comes the vararg which complains and cries like a baby:

public static void main(String[] args)
{
    int a = 14;
    Integer b = new Integer(14);
    stuff(a); // Doesn't compile (ambiguity)
    stuff(b); // Doesn't compile (ambiguity)
}

static void stuff(int... arg) { System.out.println("varargs int"); }
static void stuff(Integer... arg) { System.out.println("varargs Integer"); }
user218046
  • 623
  • 6
  • 20
  • 2
    Because of [autoboxing](https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html), so in practice those two methods are actually the same. – m0skit0 Mar 13 '17 at 10:03
  • 2
    Because of autoboxing, Java knows that if you pass ints to the function, they could be converted to Integers. However, that means that both method are candidates. As humans we're better and know which is the most likely. – Steve Smith Mar 13 '17 at 10:04
  • No, sorry, I think that's not enough. Inside of `stuff(int... arg)` arg has the type `int[]`, so why should the parameters be converted to `Integer`? – Axel Mar 13 '17 at 10:40
  • See here for a deeper explanation: http://stackoverflow.com/questions/36384527/why-ambiguous-error-when-using-varargs-overloading-with-primitive-type-and-wrapp – Tim Biegeleisen Mar 13 '17 at 11:56

2 Answers2

3

The problem is:

java is doing behind the scenes bridge methods (you need to verify that is you need deep info)

AND the important part, vargargs means too YOU CAN JUST NOT PASS ANY PARAMETER, so:

static void stuff(int... arg)   

and

static void stuff(Integer... arg) 

can both being invoked taking no parameters... so that will create some conflict about what method should the JVM invoke

ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
  • Well, is that because of autoboxing or because of this, or are those 2 reasons tied together in this case? – Shadov Mar 13 '17 at 10:05
  • 1
    I created two methods named `check`, one with argument `String...` the other one with `Integer...` and it compiles (unless I actually call it with no arguments, then it doesn't compile) – Shadov Mar 13 '17 at 10:11
  • @Whatzs It won't compile if you pass them `null` too. In that case you need to cast `null` to the correct type to tell the compiler which method you want to call: `check((Integer) null)` – BackSlash Mar 13 '17 at 10:46
3

Consider the following two hypothetical calls to stuff():

int a = 14;
Integer b = new Integer(14);

stuff(a, b);
stuff(b, a);

How does the compiler even know which method should be called here? Because of autoboxing rules, either call could be referring to either overloaded method.

Update:

My answer is logically correct, or at least on the right track, but for a more formal answer we can refer to this SO question:

Why ambiguous error when using varargs overloading with primitive type and wrapper class?

The two varargs method are invoked in loose invocation context. As a result, the compiler will attempt to find the more specific method via JLS 15.12.2.5 Choosing the Most Specific Method. However, since neither int nor Integer are subtypes of one another, the compiler will throw an error.

Community
  • 1
  • 1
Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • But he did not call the method with two parameters. While in that case it would surely be ambigous, I think in this case it is not obvious. – Axel Mar 13 '17 at 10:43