Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why List<Integer[]> listOfArrays = Arrays.asList(new Integer[]{1, 2}) doesn't compile? [duplicate]

1) OK

List<int[]> listOfArrays1 = Arrays.asList( new int[]{1, 2} );

2) OK

List<int[]> listOfArrays2 = Arrays.asList( new int[]{1, 2}, new int[]{3, 4} );

3) Compile error Type mismatch: cannot convert from List<Integer> to List<Integer[]>

List<Integer[]> listOfArrays3 = Arrays.asList( new Integer[]{1, 2} );

4) OK

List<Integer[]> listOfArrays4 = Arrays.asList( new Integer[]{1, 2},  new Integer[]{3, 4} );

This is the signature for asList: public static <T> List<T> asList(T... a)

asList expects 0 or more "a" of type T. My "a" is new Integer[]{1, 2} and it is of type Integer[]. So, why is it generating a List<Integer> instead of a List<Integer[]>?

like image 209
Gustavo Avatar asked Oct 18 '22 05:10

Gustavo


1 Answers

Let's look at the problem example (3rd):

List<Integer[]> listOfArrays3 = Arrays.asList( new Integer[]{1, 2} );

As you showed, the method signature is:

public static <T> List<T> asList(T... a)

In this particular case, the single Integer[] is being considered for the T.... An array or an unspecified number of the same object can be supplied to T.... Since you specified one array, the T is regarded as Integer (and T... becomes Integer[]).

When you supply an int[] as a single argument (1st), the compiler doesn't automatically wrap this to an Integer[] because such an object is different from an int[]. Because int is not an object, the only object type that can fit T is int[] (which builds the parameter as an int[][]).

Supplying two int[]s (2nd) is much more obvious, as the compiler can only regard two arrays for T... as int[]s, thus T... is also int[][].

When you supply two Integer[]s (4th), it is more obvious again that the compiler has no choice but to regard the two parameters which make up T... as Integer[] (which becomes a single array: Integer[][]).

Edit: Supplying an array as a vararg:

You can supply a single array as a vararg. Let's take an example without a generic:

public int iLoveMeSomeInts(int...nums)

Supplying an int[] to this method as an argument does work. The array is regarded as a vararg of ints for the purposes of validating the signature, then the vararg is regarded as an int[] for the method's internal logic.

The difference in your example is that the argument is T.... A generic T must be an object, so the compiler cannot regard an int[] as a vararg of int... in this case. The compiler then has no choice but to regard the int[] as a single element in a vararg of int[]... (because int[] is an object). There is no ambiguity in this.

However, because Integer is an object, the compiler will use a single Integer[] as Integer....

What's even cooler is this: if you wanted an Integer[] returned using the method in question, and still only supplied a single Integer[], you could call:

Arrays.<Integer[]>asList(new Integer[] {1, 2});

This forces the compiler to regard your single Integer[] as Integer[]....

like image 65
Zircon Avatar answered Oct 21 '22 03:10

Zircon