5

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[]>?

4
  • Please explain how 1 and 2 didn't show any error. List doesn't work with primitive int. Commented Jul 15, 2016 at 13:48
  • 2
    @Sufian int[] is not primitive. It's an object. Commented Jul 15, 2016 at 13:48
  • (1) resolves correctly is because T can be int[] but not int. Related stackoverflow.com/questions/2721546/… Commented Jul 15, 2016 at 13:55
  • OP, I suggest you read the answers in the chain of duplicate questions that have been marked here and determine if they are at all satisfactory (I don't think they are). If not, edit your question and at the top explain why you think this is not a duplicate. Maybe then the mark will be removed. Commented Jul 15, 2016 at 15:07

1 Answer 1

3

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[]....

Sign up to request clarification or add additional context in comments.

11 Comments

I guess I didn't really know how varargs work.
varvargs are great, because you can supply any number of the same object, and in the method itself that argument is treated as an array. The gotcha here is that a generic T must be an object, so supplying an int[] will not count as a vararg of ints.
So in other words (if I understood this correctly), case 3 is ambiguous because it can be interpreted as both two arguments (1, 2) and one argument (new Integer[]{1,2}). It happens to be the case that the compiler decides to choose the first one and if you are expecting the second outcome, you get surprised.
Close, but it's not ambiguous at all. You can supply a single array for varargs. I will clarify this for you in an edit of the answer.
They could have, but it would be somewhat self-defeating. It's convenient to pass a single array as a vararg. If you had a full-and-ready Integer[] you wanted to pass as Integer..., it would be much more complicated (and not very intuitive) to get each element and pass them as separate arguments. In contrast, if you had a single Integer[] you wanted to pass as an Integer[]..., you could either force it via the statement i showed or, if you didn't know about it, pass the argument as new Integer[][] { myIntegerArray }.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.