Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array of Generic List

Tags:

java

generics

I am playing with Generic and arrays, it seems the following code compiles fine,

ArrayList<Key> a = new ArrayList<Key>(); 

But the compiler complains about this one,

ArrayList<Key>[] a = new ArrayList<Key>[10]; 

By reading post in stackoverflow, I sort of understand that this is due to Type Erasure and I can fix it by using,

ArrayList<Key>[] a = (ArrayList<Key> []) new ArrayList[10]; 

or list of list

ArrayList<ArrayList<Key>> b = new ArrayList<ArrayList<Key>>(); 

But I can't figure out the reason behind the scene. Especially, why the second one is illegal given the first one is perfectly OK. And why the compiler does not complain about the list of list.

like image 353
Hong Avatar asked Oct 18 '11 15:10

Hong


People also ask

What is a generic ArrayList?

(ArrayList API documentation) ArrayList is a generic container that gives us array-like convenience for accessing elements (the method . get(i) gives us access by index) with linked-list like convenience for adding new elements (the method .

Can you make an array of generics?

Array of generic typesNo, we cannot create an array of generic type objects if you try to do so, a compile time error is generated.

Is ArrayList a generic type?

As of Java SE 5.0, ArrayList is a generic class with a type parameter. To specify the type of the element objects that the array list holds, you append a class name enclosed in angle brackets, such as ArrayList<Employee>.


2 Answers

You can't have an array, because an array requires a raw type. You typecast it in the second instance, which makes it fit the defined type, and is therefore legal (however, this is impossible for it to infer). The list of list is legal as ArrayList isn't an array.

Read chapter 7.3 (page 15) in the official tutorial for more details on this.

The component type of an array object may not be a type variable or a parameterized type, unless it is an (unbounded) wildcard type.You can declare array types whose element type is a type variable or a parameterized type, but not array objects. This is annoying, to be sure. This restriction is necessary to avoid situations like:

List<String>[] lsa = new List<String>[10]; // not really allowed Object o = lsa; Object[] oa = (Object[]) o; List<Integer> li = new ArrayList<Integer>(); li.add(new Integer(3)); oa[1] = li; // unsound, but passes run time store check String s = lsa[1].get(0); // run-time error - ClassCastException 

If arrays of parameterized type were allowed, the example above would compile without any unchecked warnings, and yet fail at run-time.

The tutorial then goes on to say the following:

Since type variables don’t exist at run time, there is no way to determine what the actual array type would be. The way to work around these kinds of limitations is to use class literals as run time type tokens

like image 117
Chris Dennett Avatar answered Sep 18 '22 05:09

Chris Dennett


Array was poor man's generics; with real generics, one should avoid arrays, though not always possible.

Arrays are covariant, generics are invariant; combined with erasure, things just don't fit very well, as illustrated by the example in Chris's answer.

However I think it is possible to relax the spec to allow generic array creation - there's really no problem there. The danger comes when up casting the array; a compiler warning at that point is enough.

Actually Java does create generic arrays for vararg methods, so it's a little hypocritical.

Here are utility methods taking advantage of that fact

@SafeVarargs static <E> E[] arrayLiteral(E... array) {     return array; }  @SafeVarargs static <E> E[] newArray(int length, E... array) {     return Arrays.copyOf(array, length); }  // usage      List<String>[] array1 = arrayLiteral(list, list);      List<String>[] array2 = newArray(10); 
like image 27
irreputable Avatar answered Sep 19 '22 05:09

irreputable