Why java does not autobox int[] to Integer[]
Asked Answered
I

5

11

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?

Isolation answered 22/10, 2013 at 4:14 Comment(0)
D
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:

Disclose answered 22/10, 2013 at 4:16 Comment(0)
A
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.

Anderson answered 22/10, 2013 at 4:29 Comment(3)
Thank you Makoto. Your answer and references helps a lot.Isolation
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...Gamut
...could yield a different object from the one that was passed in.Gamut
C
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
Cirillo answered 22/10, 2013 at 4:32 Comment(3)
+1 for the detailed clear answer. I guess StackOverFlow must have an option to accept multiple answers.Isolation
@NamalFernando thanks for the praise. Unfortunately SO doesn't provide such function, but you are free to award me with bounty ;)Cirillo
Probably the only answer that knows why it must not be done, even if possible to add syntactic sugar to the compile.Hashimoto
V
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.

Viddah answered 22/10, 2013 at 4:18 Comment(0)
R
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.

Running answered 22/10, 2013 at 4:47 Comment(1)
Thank you. Got your answer. But my concern was why it is not autoboxing? Any way I got it from Rohit.Isolation

© 2022 - 2024 — McMap. All rights reserved.