8

If I write the Java method

public static void f(int... x) {
    for (int a: x) {
        System.out.println(a);
    }
}

then I can call this method via

f(1, 2, 3);

as well as

f(new int[]{1, 2, 3});

and both calls are treated exactly the same. However, the two calls

Arrays.asList(1, 2, 3)              // (a) produces a three-element Integer list

and

Arrays.asList(new int[]{1, 2, 3})   // (b) produces a one-element list of Integer arrays

are not treated the same. The section on evaluating arguments in the JLS states "The final formal parameter of m necessarily has type T[] for some T" so why isn't the "final formal parameter" in case (b) above not an integer array which would create a three-element list, like case (a)?

The only thing I can think of is that Arrays.asList is generic, and something about type compatibility (mentioned in JLS Section 15.12.4.2) is at play here, but I can't quite put my finger on the actual sentence in the JLS that makes the two cases different.

The commentary in the JLS talks about the need to craft these semantics carefully in order to handle the interplay between "parameterized types and array types that occurs in a Java Virtual Machine with erased generics" but what we end up is my function f and Arrays.asList appearing to behave inconsistent. In the former case I can "unpack" or "pack" my args and all is the same; in the latter case, the two cases are different.

How is this explained in language-lawyer terms?

1
  • I have a feeling you can reproduce the apparent inconsistency with public static void f(Object... x) or public T static void f(T... x) .. (not at a comp now so can't try) Commented Nov 26, 2014 at 12:22

2 Answers 2

5

Arrays.asList is defined as having parameter T..., and the body will see it as one argument of type T[]. However, T must be a reference type (like any type parameter), and int is not a reference type. Because of that, there's no way to make new int[]{...} compatible with an array for varargs purposes. (And the result would be List<int> which isn't allowed.) The only alternative is to treat it as a single object, and thus T here will be int[], which is a reference type, and the function will return a List<int[]>.

I think that's the reason, although I would still need to look up the exact language. It probably involves the type inference rules, which I haven't mastered.

However, I did try this:

List x = Arrays.asList(new int[]{1, 2, 3});
List y = Arrays.asList(new Integer[]{1, 2, 3});
System.out.println(x.size());   
System.out.println(y.size());   

(note that I deliberately used a List raw type, something I wouldn't do in real code). The output:

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

1 Comment

I agree, when the params are ints, each gets boxed to be a reference type, while int[] is already a reference type
2
    Arrays.asList(1, 2, 3);

1 2 3 are autoboxed to Integer objects which are then placed in an Object[]

    Arrays.asList(new int[]{1, 2, 3});

forces the 3 integers into a primitive int array.

Arrays.asList() expects Object[], so it places your int[] array into a single element Object[]

2 Comments

"Arrays.asList() expects Object[]" or T[] for any reference type T
agreed. the winning answer explains it in better detail than me. the answer didn't exist when i wrote mine. <sobs uncontrollably>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.