Java Reference
In-Depth Information
Obviously, this is a serious constraint. You don't want the binary tree implementation to be as rigid as that.
As long as there's an implementation of Comparable<T> in a class that allows objects to be compared, that
should suffice. What you really want is for your BinaryTree<T> type to accept any type argument that is
of a type that implements Comparable<T> for the type itself, or for any superclass of the type. You don't
have the tools to deal with this at this point, but I'll return to the solution to this problem a little later in this
chapter.
VARIABLES OF A RAW TYPE
You have seen that the runtime type of all instances of a generic type is the same and is just the generic type
name without any parameters. You can use the generic type name by itself to define variables. For example:
LinkedList list = null;
This creates a variable with the name list that is of type LinkedList from the LinkedList<T> generic
type. This type that results from eliminating the parameters from the generic type is referred to as a rawtype .
The class that corresponds to the raw type is produced by removing the type parameters from the generic
type definition and replacing each instance of a type variable in the definition by the leftmost bound of its
corresponding type parameter. This process of mapping from a generic type to a non-generic type is called
type erasure because all occurrences of the type variable are effectively erased from the generic class defin-
ition. A raw type exists as a consequence of implementing generic types using type erasure.
In the absence of any explicit type parameter bounds, every type parameter T is implicitly bounded by
type Object , so all occurrences of T in a generic type definition are replaced by Object to produce the
raw type. This is important for interface types such as Iterable<T> and Comparable<T> in the standard
packages. Interfaces in the standard packages that define methods are generally defined as generic types for
maximum flexibility. When you implement such an interface in an ordinary class without specifying a type
argument, your class is implementing the raw type, so the methods in the interface are declared with para-
meters and/or return types of type Object .
Suppose you have specified that the type parameter T for a parameterized type is bounded by the type
Comparable<T> . This is the case for the BinaryTree<T> type that you implemented earlier. In the raw type
for the parameterized type, all occurrences of the type variable T are replaced by Comparable . The raw type
corresponding to Comparable<T> is produced by using type Object as the replacement for the type paramet-
er because no parameter constraints are specified for the Comparable<T> type. Thus for the BinaryTree<T>
type, the raw type definition is produced by substituting Comparable in place of the type variable, T . This
may be what you want for a valid raw type in this case. The parameter type to the add() method is Compar-
able , so you can pass an object of any class type that implements the Comparable interface to it. However,
in other instances where methods with a return type are specified by a type parameter, you may want the raw
type to be produced using Object as the upper bound for the type parameter. This applies to the serializable
version of the LinkedList<T> generic type where the bound on the type parameter is Serializable . It
might be better to have the getFirst() and getNext() methods return a reference of type Object instead
of type Serializable . You can accomplish this quite easily by simply defining the first bound for the type
parameter as type Object , like this:
class LinkedList<T extends Object & Serializable> implements Serializable {
// Class definition as before...
Search WWH ::




Custom Search