List <String> l1 = new ArrayList<String>(); List<Integer> l2 = new ArrayList<Integer>(); System.out.println(l1.getClass() == l2.getClass());
false
, but you'd be wrong. It prints
true
, because all instances of a generic class have the same
run-time class, regardless of their actual type parameters.
Indeed, what makes a class generic is the fact that it has the same behavior for all of its possible type parameters; the same class can be viewed as having many different types.
As consequence, the static variables and methods of a class are also shared among all the instances. That is why it is illegal to refer to the type parameters of a type declaration in a static method or initializer, or in the declaration or initializer of a static variable.
Collection cs = new ArrayList<String>(); if (cs instanceof Collection<String>) { ...} // Illegal.
Collection<String> cstr = (Collection<String>) cs; // Unchecked warning,
The same is true of type variables
<T> T badCast(T t, Object o) {return (T) o; // Unchecked warning. }
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.
However, you can still use wildcard arrays. The following
variation on the previous code forgoes the use of both array objects
and array types whose element type is parameterized. As a result,
we have to cast explicitly to get a String
out of the array.
List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type. Object o = lsa; Object[] oa = (Object[]) o; List<Integer> li = new ArrayList<Integer>(); li.add(new Integer(3)); oa[1] = li; // Correct. String s = (String) lsa[1].get(0); // Run time error, but cast is explicit.
List<String>[] lsa = new List<?>[10]; // Error.
<T> T[] makeArray(T t) { return new T[100]; // Error. }
The way to work around these kinds of limitations is to use class literals as run time type tokens, as described in the next section, Class Literals as Runtime-Type Tokens.