11.1 泛型和类型安全的容器
1、使用ArrayList相当简单:创建一个实例,用add插入对象;然后用get()返回这些对象,此时需要使用索引,就像数组一样,但是不需要方括号。ArrayList还有一个size()方法。使你可以知道已经有多少元素添加了进来从而不会不小心因索引越界而引发错误。
2、应用预定义的泛型通常会很简单。例如,要想定义用来保存Apple对象的ArrayList,你可以声明ArrayList<Apple>,其中尖括号括起来的是类型参数(可以有多个),它指定了这个容器实例可以保存的类型。通过使用泛型,就可以在编译期防止将错误类型的对象放置到容器中。
public class ApplesAndOrangesWithGenerics { public static void main(String[] args) { ArrayListapples = new ArrayList (); for(int i = 0; i < 3; i++) apples.add(new Apple()); // Compile-time error: // apples.add(new Orange()); for(int i = 0; i < apples.size(); i++) System.out.println(apples.get(i).id()); // Using foreach: for(Apple c : apples) System.out.println(c.id()); }
(1)编译器可以防止你将orange放置到Apple中,因此它编程了一个编译期错误,而不再是运行时错误。
(2)通过使用泛型,你不仅知道编译器将会检查你放置到容器的对象类型,而且在使用容器中的对象时,可以使用更加清晰的语法(不用再类型转换)
11.2 基本概念
1、java容器类类库的用途是“保存对象”,并将其划分为两个不同的概念:
(1)Collection:一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素,Set不能有重复元素,Queue按照排队规则来确定对象产生的顺序(通常与插入顺序相同)。
(2)Map:一组成对的“键值对”对象,允许你使用键来查找值。ArrayList,LinkdList,TreeMap.
11.3添加一组元素
1、Arrays.asList()方法接收一个数组或是一个用逗号分隔的元素列表(使用可变参数),并将其转化为一个List对象。
2、Collection.addAll()方法接收一个Collection对象,以及一个数组或是一个用逗号分割的列表,将元素添加到Colleciton中。
public class AddingGroups { public static void main(String[] args) { Collectioncollection = new ArrayList (Arrays.asList(1, 2, 3, 4, 5)); Integer[] moreInts = { 6, 7, 8, 9, 10 }; collection.addAll(Arrays.asList(moreInts)); // Runs significantly faster, but you can't // construct a Collection this way: Collections.addAll(collection, 11, 12, 13, 14, 15); Collections.addAll(collection, moreInts); // Produces a list "backed by" an array: List list = Arrays.asList(16, 17, 18, 19, 20); list.set(1, 99); // OK -- modify an element // list.add(21); // Runtime error because the // underlying array cannot be resized. }}
11.4容器的打印
1、你必须使用Array.toString()来产生数组的可打印表示,但是打印容器无需任何帮助。
public class PrintingContainers { static Collection fill(Collectioncollection) { collection.add("rat"); collection.add("cat"); collection.add("dog"); collection.add("dog"); return collection; } static Map fill(Map map) { map.put("rat", "Fuzzy"); map.put("cat", "Rags"); map.put("dog", "Bosco"); map.put("dog", "Spot"); return map; } public static void main(String[] args) { System.out.println(fill(new ArrayList ())); System.out.println(fill(new LinkedList ())); System.out.println(fill(new HashSet ())); System.out.println(fill(new TreeSet ())); System.out.println(fill(new LinkedHashSet ())); System.out.println(fill(new HashMap ())); System.out.println(fill(new TreeMap ())); System.out.println(fill(new LinkedHashMap ())); }} /* Output:[rat, cat, dog, dog][rat, cat, dog, dog][dog, cat, rat][cat, dog, rat][rat, cat, dog]{dog=Spot, cat=Rags, rat=Fuzzy}{cat=Rags, dog=Spot, rat=Fuzzy}{rat=Fuzzy, cat=Rags, dog=Spot}*///:~
2、Collection打印出来的内容用方括号括住,每个元素由逗号分隔。Map则用大括号括住,键和值由等号联系。
11.5 List
1、包括ArrayList和LinkedList
11.6迭代器
1、迭代器是一个对象,他的工作是遍历并选择序列中的对象。而客户端程序不必知道或关心该序列底层的结构。
2、java的iterator只能单向异动,这个iterator只能用来:
(1)使用方法iterator()要求容器返回一个iterator。iterator将准备好返回序列的第一个元素。
(2)使用next()获得序列中下一个元素。
(3)使用hasNext()检查序列中是否还有元素。
(4)使用remove()迭代器新近返回的元素删除
3、iterator的真正为例:能够将遍历序列的操作与底层的结构分离。正由于此,我们有时会说:迭代统一了对容器的访问方式。
public class CrossContainerIteration { public static void display(Iteratorit) { while(it.hasNext()) { Pet p = it.next(); System.out.print(p.id() + ":" + p + " "); } System.out.println(); } public static void main(String[] args) { ArrayList pets = Pets.arrayList(8); LinkedList petsLL = new LinkedList (pets); HashSet petsHS = new HashSet (pets); TreeSet petsTS = new TreeSet (pets); display(pets.iterator()); display(petsLL.iterator()); display(petsHS.iterator()); display(petsTS.iterator()); }} /* Output:0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx4:Pug 6:Pug 3:Mutt 1:Manx 5:Cymric 7:Manx 2:Cymric 0:Rat5:Cymric 2:Cymric 7:Manx 1:Manx 3:Mutt 6:Pug 4:Pug 0:Rat*///:~
11.6.1ListIterator
1、它只能用于各种List类的访问,并且可以双向异动。
11.7LinkedList
11.8Stack
11.9 Set
1、Set不保存重复元素。
11.10Map
public class Statistics { public static void main(String[] args) { Random rand = new Random(47); Mapm = new HashMap (); for(int i = 0; i < 10000; i++) { // Produce a number between 0 and 20: int r = rand.nextInt(20); Integer freq = m.get(r); m.put(r, freq == null ? 1 : freq + 1); } System.out.println(m); }} /* Output:{15=497, 4=481, 19=464, 8=468, 11=531, 16=533, 18=478, 3=508, 7=471, 12=521, 17=509, 2=489, 13=506, 9=549, 6=519, 1=502, 14=477, 10=513, 5=503, 0=481}*///:~
1、Map可以返回它的键的Set,它的值的Collection,或者它的键值对的Set。keySet()方法产生了由在Map中的所有键组成的Set,它在foreach语句中被用来迭代遍历该Map.
11.11Queue
1、队列是一个典型的先进先出的容器。
2、LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以用作Queue的一种实现。通过LinkenList向上转型为Queue,。
11.11.1PriorityQueue
11.12Collection和Iterator
1、Collection可以使用foreach结构,从而使代码更加清晰。
2、如果实现Collection,就必须实现iterator
11.13Foreach与迭代器
1、foreach语法主要用于数组,但是它也可以用于任何Collection对象。
2、enrtySet()产生一个由Map.Entry的元素构成的Set,并且这个Set是一个Iterable,因此它可以用于foreach循环。
3、不存在任何从数组到Iterable的自动转换,你必须手工执行这种转换。