////////////////////////////////////////////////////////////////////// // Printable interface Printable { public void print(); } ////////////////////////////////////////////////////////////////////// // INTERFACES // Without these, clients would not be able to treat named list cells // as list cells, because NamedListCell does not extend ListCell (see // below). interface IListCell { public Elem getValue(); public IListCell next(); } interface INamedListCell extends IListCell { public INamedListCell nextNamed(); } ////////////////////////////////////////////////////////////////////// // MYTYPE-PARAMETERIZED CLASSES abstract class PListCell> implements IListCell { protected final Elem value; protected final MyType next; public PListCell(Elem value, MyType next) { this.value = value; this.next = next; } public Elem getValue() { return value; } public MyType next() { return next; } } abstract class PNamedListCell> extends PListCell implements INamedListCell { public PNamedListCell(Elem value, MyType next) { super(value, next); } public INamedListCell nextNamed() { return next; } public void printAll() { this.getValue().print(); this.next().printAll(); } } ////////////////////////////////////////////////////////////////////// // CONCRETE CLASSES // Without these, you would not be able to have a finite instantiation // of the parameterized classes. class ListCell extends PListCell> { public ListCell(Elem value, ListCell next) { super(value, next); } } class NamedListCell extends PNamedListCell> { public NamedListCell(Elem value, NamedListCell next) { super(value, next); } } ////////////////////////////////////////////////////////////////////// // CLIENT class C implements Printable { public void print() { System.out.println("C"); } } public class GJRecursive { public static void main(String[] args) { IListCell cell = new NamedListCell(new C(), null); INamedListCell cell2 = new NamedListCell(new C(), null); INamedListCell cell3 = cell2.nextNamed(); } }