Implications for Nested Classes
Nested classes and interfaces can be declared as generic types, as shown in Example 11.19. All nested generic classes, except anonymous classes, can specify formal type parameters in their declaration, as at (2) through (6). Anonymous classes do not have a name, and a class name is required to declare a generic class and specifyits formal type parameters. Thus an anonymous class can only be declared as a parameterized type, where the actual type parameters are either specified in the anonymous class expression, as at (7) through (9), or can be inferred from the context when the diamond operator is used, as at (10).
Example 11.19 Generic Nested Types
class GenericTLC<A> { // (1) Top-level class
static class SMC<B> {/*…*/} // (2) Static member class
interface SMI<C> {/*…*/} // (3) Static member interface
class NSMC<D> {/*…*/} // (4) Non-static member (inner) class
void nsm() {
class NSLC<E> {/*…*/} // (5) Local (inner) class in non-static context
}
static void sm() {
class SLC<F> {/*…*/} // (6) Local (inner) class in static context
}
// Anonymous classes as parameterized types:
SMC<A> xsf = new SMC<A>() { // (7) In non-static context.
/*…*/ // A is type parameter in top-level class.
};
SMC<Integer> nsf = new SMC<Integer>() { // (8) In non-static context
/*…*/
};
static SMI<String> sf = new SMI<String>() { // (9) In static context
/*…*/
};
SMC<String> nsf1 = new SMC<>() { // (10) Using diamond operator
/*…*/
};
}
The type parameter names of a generic nested class can hide type parameter names in the enclosing context (see (2) in Example 11.20). Only a non-static nested class can use the type parameters in its enclosing context, as type parameters cannot be referenced in a static context.
Example 11.20 also illustrates instantiating generic nested classes. As a static member class does not have an outer instance, only its simple name is parameterized, and not the enclosing types, as shown by the code at (6). As a non-static member class requires an outer instance, any generic enclosing types must also be parameterized and instantiated, as shown by the code at (7). See §9.3, p. 502, for the syntax used in instantiating nested classes.
Example 11.20 Instantiating Generic Nested Classes
public class ListPool<T> { // (1) Top-level class
static class MyLinkedList<T> { // (2) Hiding type parameter in enclosing context
T t; // T refers to (2)
}
class Node<E> { // (4) Non-static member (inner) class
T t; // T refers to (1)
E e;
}
public static void main(String[] args) {
// (5) Instantiating a generic top-level class:
ListPool<String> lp = new ListPool<>();
// (6) Instantiating a generic static member class:
ListPool.MyLinkedList<String> list = new ListPool.MyLinkedList<>();
// (7) Instantiating a generic non-static member class:
ListPool<String>.Node<Integer> node1 = lp.new Node<>();
ListPool<String>.Node<Double> node2 = lp.new Node<>();
ListPool<Integer>.Node<String> node3
= new ListPool<Integer>().new Node<>();
}
}
Leave a Reply