Unchecked Assignment Java Util Arraylist Class

The class discussed earlier in this chapter has a legacy method , 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 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, , that assigns this returned litter to a collection whose type is specified to be a :

public static void main(String[] args) { Collection<Cat> litter = myCat.getLitter(3); for (Cat c : litter) { System.out.println(c.getColor()); }
When you compile you will get the following warning:
Note: Cats.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details.
Using the 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 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 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 method invokes the methods of its superclass and contained list. The methods are legacy methods because they were defined before generics became available.

When you compile 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 method is defined to return an object of type , the compiler can't verify that the collection being returned is a . However, because of the contract of the 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:

In this case, it is perfectly okay to suppress the unchecked cast warning.

It's an unchecked cast because is not known at runtime. So the runtime check can only check the cast up to (the erasure of ), but not actually up to itself. (So for example, if were , then if the object's actual runtime class was , it would not be caught by the check even though it's not .)

returns , and not (where would be the type argument of the parameter), because it can be used to create both arrays of primitives and arrays of references. Type variables like cannot represent primitive types, and the only supertype of array-of-primitive types is . objects representing primitive types are parameterized with its wrapper class as the type parameter, e.g. has type . But if you pass to , you will create an , not (which would be ). But if you pass a representing a reference type, will return an .

So basically, calling with a will always return either an , or an array of primitives. An array-of-primitives type is not a subtype of , so it would fail a runtime check for . In other words, if the result is an , it is guaranteed to be an . So even though this cast only checks up to at runtime, and it doesn't check the part from up to , in this case, the check up to is sufficient to guarantee that it is an , and so the unchecked part is not an issue in this case, and it is effectively a fully checked cast.

By the way, from the code you have shown, you do not need to pass a class object to initialize or to use . That would only be necessary if your class actually used the class at runtime. But it doesn't. All it does is create an array (that is not exposed to the outside of the class), and get elements from it. That can be achieved using an . You just need to cast to when you take an element out (which is unchecked by which we know to be safe if we only put s into it):

Categories: 1

0 Replies to “Unchecked Assignment Java Util Arraylist Class”

Leave a comment

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *