10

When I do the following,

  • arrayList1 - contains one element and it is an int[].
  • arrayList2 - not compiling (Error : The constructor ArrayList<Integer>(List<int[]>) is undefined)
  • arrayList3 - contains 7 elements and they are Integer objects

Here's the code:

int[] intArray = new int[]{2,3,4,5,6,7,8};
ArrayList arrayList1 = new ArrayList(Arrays.asList(intArray));
ArrayList<Integer> arrayList2 = new ArrayList<Integer>(Arrays.asList(intArray));

Integer[] integerArray = new Integer[]{2,3,4,5,6,7,8};
ArrayList<Integer> arrayList3 = new ArrayList<Integer>(Arrays.asList(integerArray));

Question : Why doesn't the compiler auto-box the elements in the int[] to Integer and create an ArrayList<Integer>? What is the reason behind this? Is that my stupidity or some other reason?

Makoto
  • 104,088
  • 27
  • 192
  • 230
ironwood
  • 8,936
  • 15
  • 65
  • 114

5 Answers5

14

The difference is int[] is itself an Object, whereas Integer[] is an array of references to Integer object.

Arrays.asList(T...) method takes variable arguments of some type T with no upper bounds. The erasure of that method is Arrays.asList(Object...). That means it will take variable number of arguments of any type that extends from Object.

Since int is not an Object, but a primitive type, so it can't be passed as individual element of T[], whereas int[] is an Object itself, it will go as first element of the T[] array (T... internally is a T[] only). However, Integer[] will be passed as T[], with each reference in Integer[] passed as different argument to T[].

And even if you would argue that compiler should have done the conversion from each element of int[] array to Integer, well that would be too much work for the compiler. First it would need to take each array element, and box it to Integer, then it would need to internally create an Integer[] from those elements. That is really too much. It already has a direct conversion from int[] to Object, which it follows. Although I have always wished Java allowed implicit conversion from int[] to Integer[], that would have made life simpler while working with generics, but again, that's how the language is designed.

Take a simple example:

Object[] array = new Integer[10];  // this is valid conversion
Object[] array2 = new int[10];     // this is not
Object obj = new int[10];          // this is again a valid conversion

So, in your code Arrays.asList(intArray) returns a ArrayList<int[]> and not ArrayList<Integer>. You can't pass it to the ArrayList<Integer>() constructor.


Related:

Community
  • 1
  • 1
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
3

An int[] is not the same as an Integer[].

An array has as associated Class object. The class object for an array of primitive ints is [I. The class object for an array of Integer is [Ljava/lang/Integer.

An array is itself an object, so converting between two objects of the same type is an identity conversion. Converting between two different typed objects isn't - and int[] and Integer[] are definitely different, as evidenced by the bytecode above.

Lastly, bear in mind that autoboxing would only really apply if there was an associated boxing conversion.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • Thank you Makoto. Your answer and references helps a lot. – ironwood Oct 23 '13 at 06:43
  • It would be possible to design a VM in such a fashion that one could use reference load/store operations on a `[I`, and integer load/store operations on a `[L`, with the caveat that such operations may fail with a typecast error; if that were done, then it would be possible to use an `int[]` as an `Integer[]`. The biggest difficulties would be that (1) passing an `int[]` to code expecting an `Integer[]` or vice versa would result in a huge speed penalty; (2) an attempt to store `null` into a `[L` could throw, and storing an `Integer` into what looks like an `Integer[]` and reading it back... – supercat Mar 19 '15 at 16:05
  • ...could yield a different object from the one that was passed in. – supercat Mar 19 '15 at 16:05
3

Technically it is possible to do it of course. However autoboxing/unboxing of primitive type array to wrapper type array is more than what you expect.

First look into the auto-boxing/unboxing of Java: What it does is simply a syntax sugar to save you typing the primitive wrapper code. e.g.

Integer i = 10;

Compiler knows that it is expecting an Integer, but int present instead. Therefore what the compiler doing is translating your code to:

Integer i = Integer.valueOf(10);

It does similar thing for unboxing: when in situation that it expects int but Integer is present, compiler replace it with varName.intValue()

Back to array. There are two problems we can forsee:

The first problem is, there is no straight-forward way to transform from an int array to an Integer array. You may argue that the compiler can transform

int[] intArray = ....;
Integer[] wrapperArray = intArray ;

to

Integer[] wrapperArray = new Integer[intArray.size()];
for (int i = 0; i < intArray.size(); i++) {
   wrapperArray[i] = Integer.valueOf(intArray[i]);
}

but that seems too much for a syntax sugar.

The second big problem is, when you are passing it as a parameter to a method, if autoboxing/unboxing happens for array, instead of reference of original array is passed, you are now passing the reference of a copy of the original array. In case you are changing the content of array in your method, the original array will not be affected. That can bring you lots of surprises.

e.g.

void foo(Integer[] arr) {
    arr[0] = 0;
}

// invoking foo in some code:
int[] intArr = new int[]{9,8,7,6};
foo(intArr);
// intArr[0] will still be 9, instead of 0
Adrian Shum
  • 38,812
  • 10
  • 83
  • 131
  • +1 for the detailed clear answer. I guess StackOverFlow must have an option to accept multiple answers. – ironwood Oct 23 '13 at 06:42
  • @NamalFernando thanks for the praise. Unfortunately SO doesn't provide such function, but you are free to award me with bounty ;) – Adrian Shum Oct 24 '13 at 01:38
  • Probably the only answer that knows why it must not be done, even if possible to add syntactic sugar to the compile. – DanielCuadra Nov 16 '18 at 23:11
1

Because int[] and Integer[] both are objects. First will hold primitive int values, which are not of type Object while second will store references of Integer objects, which are of type Object.

Vallabh Patade
  • 4,960
  • 6
  • 31
  • 40
1

arrayList1 is really a List of size one.

http://ideone.com/w0b1vY

arrayList1.size() = 1
arrayList3.size() = 7

The int[] is being cast to a single Object. That Object cannot be cast to Integer.

Chloe
  • 25,162
  • 40
  • 190
  • 357
  • 1
    Thank you. Got your answer. But my concern was why it is not autoboxing? Any way I got it from Rohit. – ironwood Oct 23 '13 at 06:34