Here's a question, this first code listing compiles just fine (JDK 1.6 | JDK 1.7):
ArrayList<String> a = new ArrayList<String>();
String[] s = a.toArray(new String[0]);
However, if I declare the List
reference as a raw type:
ArrayList a = new ArrayList();
String[] s = a.toArray(new String[0]);
I get a compiler error saying the String[]
is required but Object[]
was found.
This means my compiler is interpreting the generic method as returning Object[]
despite of receiving a String[]
as its argument.
I doubled-checked the toArray(myArray)
method signature:
<T> T[] toArray(T[] a);
Therefore it is a parameterized method whose type parameter <T>
has no relation whatsoever with that of the List (i.e. <E>
).
I have no idea how using a raw type here affects the evaluation of parameterized methods using independent type parameters.
- Does anyone has any idea why this code does not compile?
- Does anybody knows any reference where this behavior is documented?
This is the closest description I found in the specification to describe this observed behavior:
Based on above, and observed behavior, I think its safe to say that all generic parameter types are removed from a raw type. Of course, the use of raw types themselves is discouraged in non-legacy code:
It may be interesting that this behaviour can be "solved". Use two interfaces, a base non generic interface and a generic interface. Then the compiler knows that all functions of the base non generic interface are not generic and will treat them like this.
This behaviour is very annoying if using streams and function chaining and therefore I solve it like following.
Soution via interface inheritence:
Now you can do following without warning or problems:
There can be no type parameter's passed into the toArray() method since your ArrayList is a non-parameteterized list, it only knows that it holds Objects, that's it.
a.toArray()
will always return an Object[] array. Again, you must cast it to(String[])
(with all the dangers therein) if you want to specify that it holds the specific String type.It's not exactly what you'd expect, but if you refer to a generic class in raw form, you lose the ability to use generics in any way for instance members. It's not restricted to generic methods either, check out this:
This is the relevant part of the JLS (4.8):
When you don't use generics compiler treats it as a raw type and hence every generic type becomes
Object
and so you cannot passString[]
because it needsObject[]
So here is the deal - If you use
You are using raw type and all its instance members are replaced by its erasure counterparts. In particular each parameterized type appearing in an instance method declaration is replaced with its raw counterpart. See JLS 4.8 for details.