Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the ArrayList implementation use Object[]?

In Java ArrayList<E> implementation base on a array of objects.
Can anybody explain me why implementation of ArrayList<E> uses array Object[] for data storage instead of E[]? What the benefit of using Object[]?

like image 791
user485553 Avatar asked Dec 08 '12 10:12

user485553


2 Answers

In Java, creating an array of a generic type is not straightforward.

The simple approach does not compile:

public class Container<E> {

    E[] arr = new E[3]; // ERROR: Cannot create a generic array of E

}

Replace E with Object, and all is well (at the expense of added complexity elsewhere in the container implementation).

There are alternative approaches, but they present a different set of tradeoffs. For an extensive discussion, see How to create a generic array in Java?

like image 82
NPE Avatar answered Nov 11 '22 22:11

NPE


So first of all, realize that the actual runtime type of the array object must be Object[]. This is because arrays know their component types at runtime (different array types are actually different types at runtime), and thus you need to specify the component type in creating the array, but the ArrayList object does not know its type argument at runtime.

That said, the compile-time type of the instance variable could be declared as either Object[] or E[], with different advantages and disadvantages:

If it is declared as Object[]:

private Object[] arr;
// to create it:
arr = new Object[3];
// to get an element:
E get(int i) { return (E)arr[i]; }

The disadvantage of this is that you must cast it to E every time you take something out of it, which means you are basically using it as a pre-generics container.

If it is declared as E[]:

private E[] arr;
// to create it:
arr = (E[])new Object[3];
// to get an element:
E get(int i) { return arr[i]; }

The advantage of this is that you no longer have to cast when you get things out of it -- it provides type-checking on the uses of arr, like generic containers. The disadvantage is that, logically, the cast is lie -- we know we created an object whose runtime type is Object[], and so it is not an instance of E[], unless E is Object.

However, there is no immediate problem with doing this, because E is erased to Object inside the instance methods of the class. The only way a problem can occur is if the object is somehow exposed to the outside of the class (e.g. returned in a method, put in a public field, etc.) in a capacity that uses its type as E[] (which it's not):

// This would be bad. It would cause a class cast exception at the call site
E[] getArray() { return arr; }

But ArrayList, and indeed any properly-designed container class, would never expose an implementation detail such as its internal array to the outside. It would break abstraction, among other things. So as long as the author of this class is aware of not ever exposing this array, there is no problem with doing it this way (save perhaps confusing the next person who sees the code and is unaware of it), and is free to take advantage of the increased type-checking that this way brings.

like image 28
newacct Avatar answered Nov 11 '22 21:11

newacct