16.1. The Class Class
There is a Class object for every type. This includes each class, enum, interface, annotation, array, and the
primitive types. There is also a special Class object representing the keyword void. These objects can be
used for basic queries about the type and, for the reference types, to create new objects of that type.
The Class class is the starting point for reflection. It also provides a tool to manipulate classes, primarily for
creating objects of types whose names are specified by strings, and for loading classes using specialized
techniques, such as across the network. We look in more detail at class loading in Section 16.13 on page 435.
You get a Class object in four ways: ask an object for its Class object using its getClass method; use a
class literal (the name of the class followed by .class, as in String.class); look it up by its fully
qualified name (all packages included) using the static method Class.forName; or get it from one of the
reflection methods that return Class objects for nested classes and interfaces (such as
Class.getClasses).
15.7.1. Type Tokens
Class is a generic class, declared as Class
parameterized type corresponding to the class it represents. For example, the type of String.class is
Class
Class object for a primitive type is the same type as that of its corresponding wrapper class. For example,
the type of int.class is Class
different instances of the same type of class. Parameterized types all share the Class object of their raw
typefor example, the Class object for List
same as that for List.class, and its type is Class.
A parameterized Class type is known as the type token for a given class. The easiest way to obtain a type
token is to use a class literal, such as String.class, since this provides you with the exact type token. In
contrast, Class.forName is declared to return a wildcard, Class<?>, that represents an unidentified type
tokento use this type token effectively you need to establish its actual type, as you'll soon see. The Object
method getClass returns the type token for the type of object it is invoked on, and its return type is also
Class<?>, another wildcard. However, getClass receives special treatment by the compiler: If
getClass is invoked on a reference with static type T, then the compiler treats the return type of
getClass as being Class<?extendsT>.[1] So this works:
[1] It actually treats it as being Class<? extends S>, where S is the erasure of T.
Parameterized types share the same Class object so the erasure is used to remove any
parameterized types from the wildcard's bounds. For example, given List<String> l,
then l.getClass() has the type Class<? extends List>.
String str = "Hello";
Class
Class<? extends String> c2 =
str.getClass(); // compiler magic
but this won't compile:
Class<? extends String> c3 =
Class.forName("java.lang.String"); // INVALID