Thinking in java——Generics 发作检查类型的容器类
Dynamic type safety
Because you can pass generic containers to pre-Java SE5 code, there's still the possibility that old-style code can corrupt your containers. Java SE5 has a set of utilities in java.util.Collections to solve the type-checking problem in this situation: the static methods checkedCollection( ), checkedList( ),checkedMap( ), checkedSet( ), checkedSortedMap( ) and checkedSortedSet( ). Each of these takes the container you want to dynamically check as the first argument and the type that you want to enforce as the second argument.
A checked container will throw a ClassCastException at the point you try to insert an improper object, as opposed to a pre-generic (raw) container which would inform you that there was a problem when you pulled the object out. In the latter case, you know there's a problem but you don't know who the culprit is, but with checked containers you find out who tried to insert the bad object.
Let's look at the problem of "putting a cat in a list of dogs" using a checked container. Here,oldStyleMethod( ) represents legacy code because it takes a raw List, and the @SuppressWarnings("unchecked" ) annotation is necessary to suppress the resulting warning:
//: generics/CheckedList.java // Using Collection.checkedList(). import typeinfo.pets.Cat; import typeinfo.pets.Dog; import typeinfo.pets.Pet; import java.util.*; public class CheckedList { @SuppressWarnings("unchecked") static void oldStyleMethod(List probablyDogs) { probablyDogs.add(new Cat()); } public static void main(String[] args) { List<Dog> dogs1 = new ArrayList<Dog>(); oldStyleMethod(dogs1); // Quietly accepts a Cat List<Dog> dogs2 = Collections.checkedList( new ArrayList<Dog>(), Dog.class); try { oldStyleMethod(dogs2); // Throws an exception } catch(Exception e) { System.out.println(e); } // Derived types work fine: List<Pet> pets = Collections.checkedList( new ArrayList<Pet>(), Pet.class); pets.add(new Dog()); pets.add(new Cat()); } } /* Output: java.lang.ClassCastException: Attempt to insert class typeinfo.pets.Cat element into collection with element type class typeinfo.pets.Dog *///:~
When you run the program you'll see that the insertion of a Cat goes unchallenged by dogsi , but dogs2 immediately throws an exception upon the insertion of an incorrect type. You can also see that it's fine to put derived-type objects into a checked container that is checking for the base type.