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.
(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 .
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.
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>.
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
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With