protected Cell head;
protected Cell tail;
public void add(E item) {
Cell cell = new Cell(item);
if (tail == null)
head = tail = cell;
else {
tail.setNext(cell);
tail = cell;
}
}
public E remove() {
if (head == null)
return null;
Cell cell = head;
head = head.getNext();
if (head == null)
tail = null; // empty queue
return cell.getElement();
}
/ ... rest of methods ... /
}
This time the element type of the cell is directly tied to the element type of the queue that it is in, and there is
no need to declare Cell to be a generic class.
If you do choose to use generic inner classes, a type variable in the inner class hides any type variable with the
same name in the outer class and, as always, hiding should be avoided.
Deeply nesting types is even more of a problem when the nested types are generic. Both nested types and
generic types add an extra degree of complexity to programs, and their combination can greatly compound
that complexity.
11.2. Working with Generic Types
To use a generic type you define a suitable parameterized type that provides the desired type arguments for
each type parameter. For example, you previously saw:
SingleLinkQueue
new SingleLinkQueue
The variable queue is of type SingleLinkQueue
declares the parameterized type SingleLinkQueue
argument for each type parameter declared by the generic type.
Working with generic types requires a little more planning than working with non-generic types: When you
need to declare a field or local variable, or a method parameter or return type, you need to specify the
appropriate parameterized type that you intend to work with. For example, should a field be of type
SingleLinkQueue
queue, perhaps SingleLinkQueue