I understand generics when it comes to collections. But what does it mean in the case of the Class<T>
class? When you instantiate a Class
object, there's only one object. So why the T
parameter? What is it specifying? And why is it necessary (if it is)?
< T > is a conventional letter that stands for "Type", and it refers to the concept of Generics in Java. You can use any letter, but you'll see that 'T' is widely preferred. WHAT DOES GENERIC MEAN? Generic is a way to parameterize a class, method, or interface.
T is type parameters (also called type variables); delimited by angle brackets (<>), follows the class name. T is just a symbol, like a variable name (can be any name) declared during writing of the class file.
Generic classes encapsulate operations that are not specific to a particular data type. The most common use for generic classes is with collections like linked lists, hash tables, stacks, queues, trees, and so on.
What does \t mean in Java? This means to insert a new tab at this specific point in the text. In the below example, "\t" is used inside the println statement. It is similar to pressing the tab on our keyboard.
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.
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.
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