50

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)?

Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
Tim
  • 4,295
  • 9
  • 37
  • 49

4 Answers4

56

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 SUN Oracle has published a good article explaining all this.
2 This is different from implementations of generics without type erasure, such as one in .NET.
3 Java Generics tutorial by Oracle.
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • @dasblinkenlight: I'm sorry but I don't quite get it. Could you perhaps give me an example of how and why you would do that? – Tim Feb 23 '12 at 01:59
  • 3
    Without that, the `instance` would be of class `Object`, and you'd need to typecast to make it useful. – Thilo Feb 23 '12 at 02:01
  • is type erasure just a hack to support something that wasn't designed into the language from the start? or does it have some real benefits over non-type erasure generics (sorry if it's a stupid question, I'm not really familiar with C# style generics) – ycomp Sep 29 '15 at 11:03
  • @ycomp Type erasure is a technique of keeping generics implementation entirely within the compile phase, without "spilling" into JVM. C#'s approach, on the other hand, splits the implementation of generics across the compiler and CLR (C#'s counterpart of JVM). – Sergey Kalinichenko Sep 29 '15 at 11:49
8

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.

Community
  • 1
  • 1
MvG
  • 57,380
  • 22
  • 148
  • 276
  • @Redandwhite, I'd be happy if you could express this “+1” sentiment by a click to the nice little upwards arrow next to my question, thank you very much. :-D – MvG Sep 05 '12 at 13:41
  • By the way, how common is Java Reflection in real life? It's the only part of generics that I'm not understanding. In almost a year of professional Java development, I haven't yet found a need for Reflection, although I use generics in Collections all the time – Redandwhite Sep 05 '12 at 14:16
  • @Redandwhite, reflection is used by quite a number of frameworks, for taks like serialization (e.g. jaxb), dependency injection (e.g. guice), method enumeration (e.g. junit) and so on. So as an application developer, not using them is normal. As a library developer, it depends on the library. Note that you also need properly typed `Class` arguments for runtime type-checked containers like [`Collections.checkedList`](http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#checkedList%28java.util.List,%20java.lang.Class%29) and friends provide them. – MvG Sep 05 '12 at 14:29
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.

Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • Your argumentation doesn't seem very conclusive to me. All you say is correct, except for the “therefore”. You could very easily have a single meta class with instances representing types, without having that class be a generic. It worked that way before generics arrived. – MvG Sep 05 '12 at 14:37
0

The use of generics in the Class type is top define the type of class. If I have ' Class obj' my object obj can holds only children of Charsequence. This is an optional argument. I'm often put an '?' to avoid warnings from the Eclipse IDE if I don't need an specific type of class.

Eldius
  • 310
  • 2
  • 4