Section 5.2. Generic Library with Generic Client


5.2. Generic Library with Generic Client

Next, we update the library and client to use generics, as presented in Example 5.2. This is generic code, written for Java 5 and its version of the Collections Framework. The interface now takes a type parameter, becoming Stack<E> (analogous to List<E>), and so does the implementing class, becoming ArrayStack<E> (analogous to ArrayList<E>), but no type parameter is added to the utility class Stacks (analogous to Collections). The type Object in the signatures and bodies of push and pop is replaced by the type parameter E. Note that the constructor in ArrayStack does not require a type parameter. In the utility class, the reverse method becomes a generic method with argument and result of type Stack<T>. Appropriate type parameters are added to the client, and boxing and unboxing are now implicit.

Example 5-2. Generic library with generic client

 g/Stack.java:   interface Stack<E> {     public boolean empty();     public void push(E elt);     public E pop();   } g/ArrayStack.java:   import java.util.*;   class ArrayStack<E> implements Stack<E> {     private List<E> list;     public ArrayStack() { list = new ArrayList<E>(); }     public boolean empty() { return list.size() == 0; }     public void push(E elt) { list.add(elt); }     public E pop() {       E elt = list.remove(list.size()-1);       return elt;     }     public String toString() { return "stack"+list.toString(); }   } g/Stacks.java:   class Stacks {     public static <T> Stack<T> reverse(Stack<T> in) {       Stack<T> out = new ArrayStack<T>();       while (!in.empty()) {         T elt = in.pop();         out.push(elt);       }       return out;     }   } g/Client.java:   class Client {     public static void main(String[] args) {       Stack<Integer> stack = new ArrayStack<Integer>();       for (int i = 0; i<4; i++) stack.push(i);       assert stack.toString().equals("stack[0, 1, 2, 3]");       int top = stack.pop();       assert top == 3 && stack.toString().equals("stack[0, 1, 2]");       Stack<Integer> reverse = Stacks.reverse(stack);       assert stack.empty();       assert reverse.toString().equals("stack[2, 1, 0]");     }   } 

In short, the conversion process is straightforward: just add a few type parameters and replace occurrences of Object by the appropriate type variable. All differences between the legacy and generic versions can be spotted by comparing the highlighted portions of the two examples. The implementation of generics is designed so that the two versions generate essentially equivalent class files. Some auxiliary information about the types may differ, but the actual bytecodes to be executed will be identical. Hence, executing the legacy and generic versions yields the same results. The fact that legacy and generic sources yield identical class files eases the process of evolution, as we discuss next.




Java Generics and Collections
Java Generics and Collections
ISBN: 0596527756
EAN: 2147483647
Year: 2006
Pages: 136

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net