Casts involving type parameters or parameterized types are replaced with casts to the erasure of that
type (see discussion below).
•
A catch clause cannot declare that it catches an exception represented by a type variableeven if the
bound on that type variable is an exception type. The exact type of the exception must be known at
compile time. (You can throw an exception so referenced, however, and you can declare the type
variable in a method's throw clause.)
•
A generic class is not allowed to directly or indirectly extend Throwable. Given that you can't catch
generic exceptions there is little point in being able to declare them.
•
You cannot use a parameterized type in a class literal expression (such as
SingleLinkQueue<String>.class). This reinforces that there is but one class object.
•
The restriction on creating arrays of a parameterized type can be limiting but is essential. Consider, for
example, an implementation of List that provides a split method that returns the contents of the list split
across a number of sub-lists. It would seem reasonable to return the sublists as an array of lists. So given a
class that implements List
such a method, but you would have trouble implementing it. You cannot create an array with component type
List
"unchecked" warning (see below). The reason you cannot create a generic array such as List
correct use of the array cannot be enforced by the type system. This is because array store checks are based on
the erasure of the component type not on their actual parameterized type, so you would be allowed to store
any kind of List in an array that is supposed to have a component type of List
Not allowing you to create generic arrays avoids this problem. From the programmers perspective, it is better
to try to work with a suitable collection of a parameterized type rather than an array. For example, the split
method could be defined to return List<List
Using unbounded wildcards in array creation and instanceof is allowed for parameterized types because
such types are effectively equivalent to their raw types. For example, creating a List<?>[1] is effectively
the same as creating a List[1]an array whose component type is a raw type. However, there is one
significant difference between these two forms: The raw type permits unsafe operations but causes the
compiler to issue a warning, whereas the wildcard form prohibits unsafe operations, causing a compile-time
error.
The absence of generic type information at runtime also means that casts involving type parameters or
parameterized types may not have the desired effect: You cannot check whether an object is an instance of a
parameterized type, so a cast to that type can not be checked at runtimeexcept if all type parameters are
unbounded wildcards. In an ideal world in which everyone used generics, such casts would simply be
disallowed (as is use of instanceof). Some degree of interoperability between generic code and
non-generic code must be provided, so the casts are allowed but are replaced by casts to the erasure of the
type variable or parameterized type, usually causing the compiler to emit an "unchecked" warning (see page
745). This warns you that the cast can neither be checked at runtime nor guaranteed to be type-safe at compile
time. For example, a method with a SingleLinkQueue<?> parameter could cast it to
SingleLinkQueue
warning. At runtime, the actual cast to SingleLinkQueue would succeed even if the queue was actually of
type SingleLinkQueue
queue. This violation would only be detected when a remove invocation tried to cast the returned instance to
Number, resulting in a runtime ClassCastException. Note, however, that if the cast does not involve a
change to the type parameter, then the cast is quite safe and there is no warning. For example, a cast from
Collection
Casts involving parameterized types are unavoidable in many circumstances, such as when a method returns a
(possibly non-generic) supertype, and the actual object will be of a generic subtype that you need to cast to
that subtype. In such circumstances you should use casts that only involve unbounded wildcards, and assign
the results to variables that also declare unbounded wildcards. The fact that you need a cast means that you
have lost valuable type information and there is no way to restore that information at runtime, so casting to a