Overloading methods with var-args - combined with boxing and widening
Asked Answered
C

3

5

When overloading methods that contain parameters that dont match, the JVM will always use the method with the smallest argument that is wider than the parameter.

I have confirmed the above with the following two examples:

Widening: byte widened to int

class ScjpTest{

    static void go(int x){System.out.println("In Int");}
    static void go(long x){System.out.println("In long");}

    public static void main (String[] args){

        byte b = 5;

        go(b);

    }

}

Boxing: int boxed to Integer

class ScjpTest{

    static void go(Integer x){System.out.println("In Int");}
    static void go(Long x){System.out.println("In Long");}

    public static void main (String[] args){

        int b = 5;

        go(b);

    }

}

Both the above examples output "In Int" which is correct. I am confused though when the situation involve var-args as shown in the following example

class ScjpTest{

    static void go(int... x){System.out.println("In Int");}
    static void go(long... x){System.out.println("In lInt");}

    public static void main (String[] args){

        byte b = 5;   //or even with:  int b = 5

        go(b);

    }

}

The above produces the following error:

ScjpTest.java:14: reference to go is ambiguous, both method go(int...) in ScjpTest and method go(long...) in ScjpTest match
                go(b);
                ^
1 error

Why does it not apply the same rule as in the previous examples? i.e. widen the byte to an int as it is the smallest that is larger than byte?

Chaos answered 14/8, 2011 at 12:54 Comment(1)
On Java 7, your last example works fine.Tattle
S
5

var-args syntax is just a alias to passing array as an argument:

foo(int ... arg) is equal to foo(int[] arg)

But arrays are not hierarchical. String[] is not a subclass of Object[]. Exactly the same rule is relevant for the method arguments. Therefore compiler cannot distinguish between 2 overloaded methods that accept long[] and int[] when you are passing byte.

Spillar answered 14/8, 2011 at 13:5 Comment(2)
Wrong. String[] is a subclass of Object[]. Arrays are covariant in Java (but not generics). See my answer: it's actually a bug in older Java versions that it does not work. The example of ziggy does work in Java 7.Tattle
... but actually what is at play in this example is not even array inheritance but widening conversions of primitive types.Tattle
T
1

It actually works in Java 7: it returns "In Int" for the varargs example too. I guess it was just a missing feature in previous versions. I don't know what Java version you are using but maybe it is also working for Java 6.

However I must say that I was surprised that even your first example works (without the varargs). I was not aware of primitive widening conversions. By the way, your first and last examples fail if you instead use Byte, Integer and Long since there is no hierarchy between those types (except that they are all subclasses of Number).

Tattle answered 14/8, 2011 at 13:39 Comment(0)
H
1

As AlexR pointed out, var-args is just like an array. Arrays of primitives (such as byte[] short[] int[] long[] float[] double[] seem to be internally compiled to the same class. That's why your overloaded methods are ambiguous. However the following code is perfectly valid:
static void go(int... x){System.out.println("In Int");}
static void go(Long... x){System.out.println("In lInt");}

This compiles successfully (since int[] and Long[] are different types), and produces the output In Int.
If you're preparing for SCJP, I would highly recommend you reading book SCJP Sun Certified Programmer for Java 6 Exam 310-065. The section Overloading in this book covers all the tricks with mixing boxing and var-args.

Handgun answered 14/8, 2011 at 13:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.