The JavaTM Tutorial
Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search
Feedback Form

Trail: Learning the Java Language
Lesson: Classes and Inheritance

Using Generics with Legacy Code

The Cat class discussed earlier in this chapter has a legacy method getLitter, that returns a collection of Cat objects:
public Collection getLitter(int size) {
    ArrayList litter = new ArrayList(size);
    for (int i = 0; i < size; i++) {
        litter.add(i, new Cat());
        return litter;
    }
}
Note that the Collection object is a raw type; the type of object contained in the collection is not specified. This situation exists for all methods that return collections before generics became available.

Suppose you write a new program, Cats, that assigns this returned litter to a collection whose type is specified to be a Cat:

public static void main(String[] args) {
Collection<Cat> litter = myCat.getLitter(3);
for (Cat c : litter) { 
    System.out.println(c.getColor());
}
When you compile Cats.java you will get the following warning:
Note: Cats.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Using the Xlint:checked flag provides this information:
% javac -Xlint:unchecked Cats.java
Cats.java:5: warning: [unchecked] unchecked conversion
found   : java.util.Collection
required: java.util.Collection<Cat>
                Collection<Cat> litter = myCat.getLitter(3);
                                                    ^
In addition, if Cat is recompiled with a compiler that supports generics, the following warning will result:
% javac -Xlint:unchecked Cat.java
Cat.java:19: warning: [unchecked] unchecked call to
add(int,E) as a member of the raw type java.util.ArrayList
                                 litter.add(i, new Cat());
                                           ^
Though the code is correct, these warnings indicate that the compiler can't guarantee the correctness of the operations, the way it can when using collections whose types are specified throughout. Whenever you get an unchecked warning, you should verify that the operation that gives rise to the warning is really correct.

Finally, let's look at a complete listing of the Stack2 class:

public class Stack2<T> implements Cloneable {
    private ArrayList<T> items;
    private int top=0;

    public Stack2() {
        items = new ArrayList<T>();
    }
    public void push(T item) {
        items.add(item);
        top++;
    }

    public T pop() {
        if (items.size() == 0)
        throw new EmptyStackException();
        T obj = items.get(--top);
        return obj;
    }

    public boolean isEmpty() {
        if (items.size() == 0)
            return true;
        else
            return false;
    }

    protected Stack2<T> clone() {
        try {
            Stack2<T> s = (Stack2<T>)super.clone(); 
            // Clone the stack
            s.items =  (ArrayList<T>)items.clone(); 
            // Clone the list
            return s; // Return the clone
        } catch (CloneNotSupportedException e) {
            //This shouldn't happen because Stack is Cloneable
            throw new InternalError();
        }
    }
}
Notice that the clone method invokes the clone methods of its superclass and contained list. The clone methods are legacy methods because they were defined before generics became available.

When you compile Stack2.java you will get the following warning:

% javac -Xlint:unchecked Stack2.java
Stack2.java:32: warning: [unchecked] unchecked cast
found   : java.lang.Object
required: Stack2<T>
         Stack2<T> s = (Stack2<T>)super.clone(); //clone the stack
                                             ^
Stack2.java:33: warning: [unchecked] unchecked cast
found   : java.lang.Object
required: java.util.ArrayList<T>
         s.items =  (ArrayList<T>)items.clone(); //clone the list
                                             ^
2 warnings
These warnings indicate that the compiler can't guarantee the correctness of the cast. In other words, because the clone method is defined to return an object of type Object, the compiler can't verify that the collection being returned is a Stack2<T>. However, because of the contract of the clone method, the assignment is legal, though it generates an unchecked warning.

There are many subtleties to using generics and interoperating with legacy code. For further information on generics see:


Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search
Feedback Form

Copyright 1995-2005 Sun Microsystems, Inc. All rights reserved.