Java Reference
In-Depth Information
element is permitted, but because
List<?>
is a parameterized type, the language requires stronger
type-checking. To avoid the possibility of a
ClassCastException
, the compiler won't let you insert
any element except
null
into a list of type
List<?>
.
Raw types are a concession to existing code, which could not use generics prior to release 5.0.
Many core library classes, such as collections, have been modified to take advantage of generics,
but existing clients of those classes continue to behave as in previous releases. The behavior of raw
types and their members was designed to mirror the pre-5 language, so as to retain compatibility.
The real problem with the
Pair
program is that the author did not decide what version of Java to
use. Although most of the program uses generics, the variable
p
is declared with a raw type. To
avoid bewildering compile-time errors,
avoid writing raw types in code intended for release 5.0
or later.
If an existing library method returns a raw type, store its result in a variable of an
appropriate parameterized type. Better yet, upgrade to a version of the library that use generics, if
possible. Although Java provides graceful interoperability between raw and parameterized types,
limitations of raw types can interfere with the utility of generics.
This issue can arise in practice when reading
Class
annotations at run time with the
getAnnotation
method, which was added to class
Class
in release 5.0. Two
Class
objects are
involved in each invocation of
getAnnotation
: the object on which the invocation is made and the
object that is passed to indicate which annotation is desired. In a typical invocation, the former is
obtained reflectively; the latter is a class literal, as in the following example:
Author a = Class.forName(name).getAnnotation(Author.class);
You do not have to cast the return value from
getAnnotation
to
Author
. Two things conspire to
make this work: (1) The
getAnnotation
method is generic. It infers its return type from its
parameter type. Specifically, it takes a parameter of type
Class<T>
and returns a value of type
T
. (2)
Class literals provide generic type information. For example, the type of
Author.class
is
Class<Author>
. The class literal conveys both run-time and compile-time type information. Class
literals used in this fashion are known as
type tokens
[Bracha04]
.
In contrast to class literals,
Class
objects obtained through reflection do not provide full generic
type information: The return type of
Class.forName
is the wildcard type
Class<?>
. It is critical that
you use this wildcard type rather than the raw type
Class
for the expression on which you invoke
the
getAnnotation
method. If you use the raw type, the returned annotation will have the compile-
time type of
Annotation
instead of the type indicated by the class literal. The following program
fragment, which violates this advice, won't compile for the same reason that the original program in
this puzzle did not:
Class
c = Class.forName(name);
// Raw type!
Author a = c.getAnnotation(Author.class); // Type mismatch
Search WWH ::
Custom Search