Generic Types and Parameterized Types – Generics

11.2 Generic Types and Parameterized Types

We first introduce the basic terminology and concepts relating to generics in Java. Note that the discussion here on generic and parameterized types also applies to enum types (§5.13, p. 287) and record classes (§5.14, p. 299).

Generic Types

A generic type is a reference type that defines a list of formal type parameters or type variables that must be provided before it can be used as a type. Example 11.2 declares a generic type which, in this case, is a generic class called Node<E> that allows nodes of specific types to be maintained. It has only one formal type parameter, E, that represents the type of the data in a node.

class Node<E> {

}

The formal type parameter E does not explicitly specify a type, but serves as a placeholder for a type to be defined in an invocation of the generic type. The formal type parameters of a generic type are specified within angle brackets, <>, immediately after the class name. A type parameter is an unqualified identifier. If a generic class has several formal type parameters, these are specified as a comma-separated list, <T1, T2, …, Tn>. It is quite common to use one-letter names for formal type parameters; a convention that we will follow in this book. For example, E is used for the type of elements in a collection, K and V are used for the type of the keys and the type of the values in a map, and T is used to represent an arbitrary type.

As a starting point for declaring a generic class, we can begin with a class where the Object type is utilized to generalize the use of the class. In Example 11.2, the declaration of the generic class Node<E> uses E in all the places where the type Object was used in the declaration of the class LegacyNode in Example 11.1. From the declaration of the class Node<E>, we can see that the formal type E is used like a reference type in the class body: as a field type at (1), as a return type at (5), and as a parameter type in the methods at (4) to (8). Use of the class name in the generic class declaration is parameterized by the type parameter ((2), (6), (7)), with one notable exception: The formal type parameter is not specified after the class name in the constructor declaration at (3). Which actual reference type the formal type parameter E represents is not known in the generic class Node<E>. Therefore, we can only call methods that are inherited from the Object class on the field data, as these methods are inherited by all objects, regardless of their object type. One such example is the call to the toString() method in the method declaration at (8).

The scope of the type parameter E of the generic type includes any non-static inner classes, but excludes any static member types—the parameter E cannot be accessed in static context. It also excludes any nested generic declarations where the same name is redeclared as a formal type parameter. Shadowing of type parameter names should be avoided.

Example 11.2 A Generic Class for Nodes

Click here to view code image

class Node<E> {
  private E            data;    // Data                           (1)
  private Node<E>      next;    // Reference to next node         (2)
  Node(E data, Node<E> next) {                                 // (3)
    this.data = data;
    this.next = next;
  }
  public void    setData(E data)       { this.data = data; }   // (4)
  public E       getData()             { return this.data; }   // (5)
  public void    setNext(Node<E> next) { this.next = next; }   // (6)
  public Node<E> getNext()             { return this.next; }   // (7)
  @Override public String toString() {                         // (8)
    return this.data.toString() +
           (this.next == null ? “” : “, ” + this.next.toString());
  }
}

Some Restrictions on the Use of Type Parameters in a Generic Type

A constructor declaration in a generic class cannot specify the formal type parameters of the generic class in its constructor header after the class name:

Click here to view code image

class Node<E> {
  …
  Node<E>() { … }                        // Compile-time error!
  …
}

A formal type parameter cannot be used to create a new instance, as it is not known which concrete type it represents. The following code in the declaration of the Node<E> class would be illegal:

Click here to view code image

E ref = new E();                           // Compile-time error!

A formal type parameter is a non-static type. It cannot be used in a static context, for much the same reason as an instance variable cannot be used in a static context: It is associated with objects. The compiler will report errors at (1), (2), and (3) in the code below:

Click here to view code image

class Node<E> {
  private static E e1;                          // (1) Compile-time error!
  public  static E oneStaticMethod(E e2) {      // (2) Compile-time error!
    E e3;                                       // (3) Compile-time error!
    System.out.println(e3);
  }
  // …
}

Leave a Reply

Your email address will not be published. Required fields are marked *