Why is foo(1,2,3) not passed to varargs method foo(Object... ) as an Integer[]
Asked Answered
I

5

18

Please regard the following lines of code:

public static void main(String[] args)  {
    foo(1,2,3);
    System.out.println("-------------------------------------");
    foo(new Integer(1), new Integer(2), new Integer(3));
    System.out.println("-------------------------------------");
    foo(new Integer[]{1,2,3});
    System.out.println("-------------------------------------");
    foo(new Integer[] {new Integer(1), new Integer(2), new Integer(3)});
}

public static void foo(Object... bar) {
    System.out.println("bar instanceof Integer[]:\t" + (bar instanceof Integer[]));
    System.out.println("bar[0] instanceof Integer:\t" + (bar[0] instanceof Integer));
    System.out.println("bar.getClass().isArray():\t" + bar.getClass().isArray());
}

The output of this code snippet is:

bar instanceof Integer[]:   false
bar[0] instanceof Integer:  true
bar.getClass().isArray():   true
-------------------------------------
bar instanceof Integer[]:   false
bar[0] instanceof Integer:  true
bar.getClass().isArray():   true
-------------------------------------
bar instanceof Integer[]:   true
bar[0] instanceof Integer:  true
bar.getClass().isArray():   true
-------------------------------------
bar instanceof Integer[]:   true
bar[0] instanceof Integer:  true
bar.getClass().isArray():   true

And this confuses me quite a bit! I don't understand why in case of foo(1,2,3) the term bar instanceof Integer[] is false.

If in these cases bar is not an instance of Integer[] what else is it an instance of?

Inherence answered 3/12, 2015 at 8:31 Comment(4)
I think the first and the second should be Object array but not Integer arrayPreceptive
Since you could pass a String for example to the varargs aswell it should originally be an Object[] and not an Integer[]. For the last two you are explicity passing an Integer[], so your condition will be true now.Blas
This is an interesting question! One suggestion: Try adding a test of foo(new int[]{1,2,3});. The result will go from confusing to weird!Kast
@Kast oh well :D the int[] will be interpreted as a single object instead of wrapping all the ints! Nice addition!Inherence
M
24
  • foo(1,2,3);

This one autoboxes 1, 2 and 3 to Integer(s) and since they are Object sub-types, an Object[] array is created, consisting of three Integers. An array Object[] is not Integer[] and that's why you get false.


  • foo(new Integer(1), new Integer(2), new Integer(3));

Here, no auto boxing applies, but in the end you will again have an array Object[] that consist of three Integers. Again, Object[] is not Integer[] and that's why you get false.


  • foo(new Integer[]{1,2,3});

Here you have only one argument, unlike the previous two cases, where you had three wrapped into one array. So, having only one argument Integer[], at Runtime the comparison bar instanceof Integer[] will return true, because integers is what you actually have.


  • foo(new Integer[] {new Integer(1), new Integer(2), new Integer(3)});

Same as the previous one - at Runtime you will check if the provided array Integer[] is an array of Integers, which is true.

Maw answered 3/12, 2015 at 8:37 Comment(1)
ah ok, i think i see my mistake now. I (falsely) assumed an Object[] which constists of only Integers would be an Integer[] (Thinking about it, that is of course wrong!) Thanks!Inherence
P
5

According to the Java Language Specification:

the result of the instanceof operator is true if the value of the RelationalExpression is not null and the reference could be cast (§15.16) to the ReferenceType without raising a ClassCastException.

In your case the Object[] parameter cannot be cast to an Integer[] so it returns false.

Pigtail answered 3/12, 2015 at 8:42 Comment(1)
To the cast: That's how I came to this problem in the first place ;)Inherence
C
3

the case where bar is not an array of integer is because it is an array of Object as you specified in your foo method signature: Object... args is syntactic sugar for Object[] args and when resolving to this method the compiler will create an array of Object.

In order to always have an array of Integer you could change your foo method signature to foo(Integer... args)

Champlain answered 3/12, 2015 at 8:36 Comment(0)
E
3

Varargs are just syntactic sugar for creating and passing arrays. Since you defined your method as

public static void foo(Object... bar) 

Java creates an Object[] array for you if you call the method as foo(1,2,3) or foo(new Integer(1), new Integer(2), new Integer(3)).

However, you can also pass your own array to a method which requires a varargs parameter. In this case Java does not create a new array for you, it just passes the array you created. In the last two calls you explicitly create an Integer[] array.

Expansionism answered 3/12, 2015 at 8:59 Comment(0)
I
2

In the case of calling foo(1,2,3); the compiler (in this case javac) generates the code foo(new Object[]{new Integer(1), new Integer(2), new Integer(3)}).

javac applies the rules for Varargs and Autoboxing. The compiler generates an array of Object because Object... means Object[]. Therefore bar is not an instance of Integer[]. It is just syntactic sugar.

Isolecithal answered 3/12, 2015 at 8:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.