What does the generic nature of the class Class<T> mean? What is T?
Solution 1:
Type parameter <T>
has been added to java.lang.Class
to enable one specific idiom1 - use of Class
objects as type-safe object factories. Essentially, the addition of <T>
lets you instantiate classes in a type-safe manner, like this:
T instance = myClass.newInstance();
Type parameter <T>
represents the class itself, enabling you to avoid unpleasant effects of type erasure by storing Class<T>
in a generic class or passing it in as a parameter to a generic method. Note that T
by itself would not be sufficient to complete this task2: the type of T
is erased, so it becomes java.lang.Object
under the hood.
Here is a classic example where <T>
parameter of the class becomes important. In the example below, Java compiler is able to ensure type safety, letting you produce a typed collection from a SQL string and an instance of Class<T>
. Note that the class is used as a factory, and that its type safety can be verified at compile time:
public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
Collection<T> result = new ArrayList<T>();
/* run sql query using jdbc */
for ( /* iterate over jdbc results */ ) {
T item = c.newInstance();
/* use reflection and set all of item’s fields from sql results */
result.add(item);
}
return result;
}
Since Java erases the type parameter, making it a java.lang.Object
or a class specified as the generic's upper bound, it is important to have access to the Class<T>
object inside the select
method. Since newInstance
returns an object of type <T>
, the compiler can perform type checking, eliminating a cast.
1
2 This is different from implementations of generics without type erasure, such as one in .NET.
3Java Generics tutorial by Oracle.
Solution 2:
The answer by dasblinkenlight already demonstrated one of the main uses of this parameter. There is one more aspect I consider relevant: using that parameter, you can restrict the kind of class you want to pass at a given location. So e.g.
Class<? extends Number> cls
means that cls
may be any class implementing the Number
interface. This can help catching certain errors at compile time, and makes class argument requirements more explicit.
Perhaps a comparison to the case without generics is in order
// Java ≥5 with generics // Java <5 style without generics
Class<? extends Foo> c; Class c;
Foo t1 = c.newInstance(); Foo t1 = (Foo)c.newInstance();
Object obj; Object obj;
Foo t2 = c.cast(obj); Foo t2 = (Foo)c.cast(obj);
As you can see, not having T
as an argument would require a number of explicit casts, as the corresponding methods would have to return Object
instead of T
. If Foo
itself is a generic type argument, then all those casts would be unchecked, resulting in a sequence of compiler warnings. You can suppress them, but the core issue remains: the compiler cannot check the validity of these casts unless you properly use the type argument.
Solution 3:
In Java there's a single metaclass: Class
. Its instances (only one per type exists) are used to represent classes and interfaces, therefore the T
in Class<T>
refers to the type of the class or interface that the current instance of Class
represents.