Taking an unknown type token Class<?> and turning it into a type token of a known type is a common
action when working with reflection. What you need is something that acts like a cast, but as you already
know, you can't perform casts involving parameterized types. The solution to this is another piece of "magic"
in the shape of the asSubclass method of class Class:
public <T> Class<? extends T>asSubclass(Class<T> subType)
Returns the Class object on which it is invoked, after casting it to represent
a subclass of the given Class object. If the current Class object does not
represent a type that is a subtype of subType's type (or subType itself),
then ClassCastException is thrown.
The asSubclass method doesn't change the Class object at all; it simply changes the type of the
expression it is invoked on, so we can use the additional type informationjust as a cast does. For example,
here's how you can use asSubclass with forName to fix the previous problem:
Class<? extends String> c3 =
Class.forName("java.lang.String").
asSubclass(String.class); // OK
Note that you can't convert the unknown type token to be exactly Class
Class<?extendsString> should be sufficient. Of course, String is not a practical example for using
reflection. A more typical example would be when you are loading an unknown class that implements a
known interface and you want to create an instance of that class; you'll see an example of this in the Game
class on page 436.
16.1.2. Class Inspection
The Class class provides a number of methods for obtaining information about a particular class. Some of
these provide information on the type of the classthe interfaces it implements, the class it extendsand others
return information on the members of the class, including nested classes and interfaces. You can ask if a class
represents an interface or an array, or whether a particular object is an instance of that class. We look at these
different methods over the next few pages.
The most basic Class methods are those that walk the type hierarchy, displaying information about the
interfaces implemented and the classes extended. As an example, this program prints the complete type
hierarchy of the type represented by a string passed as an argument:
import java.lang.reflect.*;
public class TypeDesc {
public static void main(String[] args) {
TypeDesc desc = new TypeDesc();
for (String name : args) {
try {
Class<?> startClass = Class.forName(name);
desc.printType(startClass, 0, basic);
} catch (ClassNotFoundException e) {
System.err.println(e); // report the error
}
}
}
// by default print on standard output
private java.io.PrintStream out = System.out;