Question

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?

Was it helpful?

Solution

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:

OTHER TIPS

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.

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

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top