容器
容器基本类型: List, Set, Queue, Map
- 泛型和类型安全的容器
class Fuji extends Apple {} ArrayList<Apple> apples = new ArrayList<Apple>(); apples.add(new Fuji()); >>> 可以添加泛型的子类 for (Apple c : apples){ >>> foreach 来遍历所有元素 System.out.println(c);
|
二.基本概念, 容器类类库的用途是:保存对象.
(一)Collection,一个独立元素的序列,这些元素都服从一条或多条规则.
所有的Collection都可以用foreach语法遍历.
List必须按照插入的顺序保存元素.
Set不能有重复元素
Queue按照排队规则来确定对象产生的顺序,通常与他们被插入的顺序相同.
(二)Map,一组成对的”键值对”对象,允许你使用键来查找值.
三.添加一组元素
Arrays asList public static <T> List<T> asList(T... a) {
Collection addAll boolean addAll(Collection<? extends E> c);
Collections addAll public static <T> boolean addAll(Collection<? super T> c, T... elements)
ArrayList public ArrayList(Collection<? extends E> c) |
Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5)); Integer[] moreInts = { 6, 7, 8, 9, 10 }; collection.addAll(Arrays.asList(moreInts)); Collections.addAll(collection, 11, 12, 13, 14, 15); Collections.addAll(collection, moreInts); List<Integer> list = Arrays.asList(16, 17, 18, 19, 20); list.set(1, 99); // list.add(21); // Runtime error because the // underlying array cannot be resized. |
四.容器的打印
static Collection fill(Collection<String> collection) { collection.add("rat"); collection.add("cat"); collection.add("dog"); collection.add("dog"); return collection; }
static Map fill(Map<String, String> 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) { print(fill(new ArrayList<String>())); print(fill(new LinkedList<String>())); print(fill(new HashSet<String>())); print(fill(new TreeSet<String>())); print(fill(new LinkedHashSet<String>()));
print(fill(new HashMap<String, String>())); print(fill(new TreeMap<String, String>())); print(fill(new LinkedHashMap<String, String>())); } 输出: [rat, cat, dog, dog] [rat, cat, dog, dog] [rat, cat, dog] [cat, dog, rat] [rat, cat, dog] {rat=Fuzzy, cat=Rags, dog=Spot} {cat=Rags, dog=Spot, rat=Fuzzy} {rat=Fuzzy, cat=Rags, dog=Spot}
|
Collection, Map 是Java容器类库中的两种主要类型, 区别在于容器中每个”槽”保存的元素个数.
Collection在每个槽中只能保存一个元素. List,它以特定的顺序保存一组元素;Set,元素不能重复;Queue,只允许在容器的一端插入对象,并从另外一端移除对象.
Map在每个槽内保存了两个对象,即键和与之相关联的值.
ArrayList和LinkedList都是List类型,都按照被插入的顺序保存元素.LinkedList包含的操作多于ArrayList. 二者的区别在于某些操作的性能.
HashSet,TreeSet,LinkedHashSet存储元素的方式不同.HashSet是最快获取元素的方式.存储没有顺序;TreeSet按照比较结果的升序保存对象;LinkedHashSet,按照被添加的顺序保存对象.
Map也被称为关联数组,可以用键来查找对象,可以看做是一个简单的数组库,键所关联的对象为值.Map会自动地调整尺寸.
HashMap提供了最快的查找速度;TreeMap按照比较结果的升序保存键;LinkedHashMap按照插入顺序保存键,同事还保留了HashMap的查询速度.
打印一个数组:
Arrays public static String toString(Object[] a) |
五.List
有两种类型的List:
ArrayList,随机访问元素速度快.但是在List的中间插入和移除元素较慢.
LinkedList,插入删除速度快,顺序访问较快,随机访问速度慢.
public boolean add(E e) public void add(int index, E element) boolean addAll(int index, Collection<? extends E> c); public boolean contains(Object o) public boolean containsAll(Collection<?> c) public E remove(int index) public boolean remove(Object o) public E get(int index) public int indexOf(Object o) { public int lastIndexOf(Object o) public List<E> subList(int fromIndex, int toIndex) boolean removeAll(Collection<?> c); boolean isEmpty(); public Object[] toArray() public <T> T[] toArray(T[] a)
Collections.sort(List) Collections public static <T extends Comparable<? super T>> void sort(List<T> list) { list.sort(null); }
ArrayList public void sort(Comparator<? super E> c) public boolean retainAll(Collection<?> c) //交集 public ArrayList() public ArrayList(Collection<? extends E> c) Collections public static void shuffle(List<?> list, Random rnd) Random rand = new Random(47); Collections.shuffle(List, rand);
Arrays public static <T> List<T> asList(T... a) |
六.迭代器
Java的Iterator只能单向移动,这个Iterator只能用来:
- 使用方法iterator()要求容器返回一个Iterator.Iterator将准备好返回序列的第一个元素.
- 使用next()获得序列中的下一个元素.
- 使用hasNext()检查序列中是否还有元素
- 使用remove()将迭代器新近返回的元素删除.
示例:
List<String> list = new ArrayList<String>(Arrays.asList("A", "B", "C")); Iterator<String> iterator1 = list.iterator(); while(iterator1.hasNext()){ System.out.print(iterator1.next() + " "); } System.out.println(); for(String str : list){ System.out.print(str + " "); } System.out.println(); Iterator<String> iterator2 = list.iterator(); for(int i = 0; i < 2; i++){ iterator2.next(); iterator2.remove(); } System.out.println(list);
输出结果: A B C A B C [C] |
ListIterator:是更加强大的Iterator的子类型.
- 可以双向移动
- 可以产生前一个和后一个元素的索引
- 使用set()替换元素
- listIterator(n)创建一个执行列表索引为n的元素处的ListIterator
List<Pet> pets = Pets.arrayList(8); ListIterator<Pet> it = pets.listIterator(); while (it.hasNext()) System.out.print(it.next() + ", " + it.nextIndex() + ", " + it.previousIndex() + "; "); System.out.println(); // Backwards: while (it.hasPrevious()) System.out.print(it.previous().id() + " "); System.out.println(); System.out.println(pets); it = pets.listIterator(3); while (it.hasNext()) { it.next(); it.set(Pets.randomPet()); } System.out.println(pets); 输出: Rat, 1, 0; Manx, 2, 1; Cymric, 3, 2; Mutt, 4, 3; Pug, 5, 4; Cymric, 6, 5; Pug, 7, 6; Manx, 8, 7; 7 6 5 4 3 2 1 0 [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug, Manx] [Rat, Manx, Cymric, Cymric, Rat, EgyptianMau, Hamster, EgyptianMau] |
七.LinkedList
LinkedList实现了基本的List接口,但是在List中进行插入和移除比ArrayList更高效,在随机访问操作要逊色一些.
LinkedList添加了可以使其用作栈,队列或双端队列的方法.
LinkedList<Pet> pets = new LinkedList<Pet>(Pets.arrayList(5)); print(pets); // Identical: print("pets.getFirst(): " + pets.getFirst()); print("pets.element(): " + pets.element()); // Only differs in empty-list behavior: print("pets.peek(): " + pets.peek()); // Identical; remove and return the first element: print("pets.remove(): " + pets.remove()); print("pets.removeFirst(): " + pets.removeFirst()); // Only differs in empty-list behavior: print("pets.poll(): " + pets.poll()); print(pets); pets.addFirst(new Rat()); print("After addFirst(): " + pets); pets.offer(Pets.randomPet()); print("After offer(): " + pets); pets.add(Pets.randomPet()); print("After add(): " + pets); pets.addLast(new Hamster()); print("After addLast(): " + pets); print("pets.removeLast(): " + pets.removeLast()); } 输出: [Rat, Manx, Cymric, Mutt, Pug] pets.getFirst(): Rat pets.element(): Rat pets.peek(): Rat pets.remove(): Rat pets.removeFirst(): Manx pets.poll(): Cymric [Mutt, Pug] After addFirst(): [Rat, Mutt, Pug] After offer(): [Rat, Mutt, Pug, Cymric] After add(): [Rat, Mutt, Pug, Cymric, Pug] After addLast(): [Rat, Mutt, Pug, Cymric, Pug, Hamster] pets.removeLast(): Hamster |
八.Stack
不建议使用java.util.Stack.
可以使用以下Stack, 或者编写一个包含LinkedList的类,用组合的方式使用LinkedList.
//: net/mindview/util/Stack.java // Making a stack from a LinkedList. package net.mindview.util; import java.util.LinkedList;
public class Stack<T> { private LinkedList<T> storage = new LinkedList<T>(); public void push(T v) { storage.addFirst(v); } public T peek() { return storage.getFirst(); } public T pop() { return storage.removeFirst(); } public boolean empty() { return storage.isEmpty(); } public String toString() { return storage.toString(); } } ///:~ |
九.Set
Set不保存重复的元素.
Set具有与Collection完全一样的接口,没有额外的功能,实际上 Set就是Collection, 只是行为不同.
HashSet使用的是散列函数.
TreeSet将元素存储在红-黑数据结构中.
LinkedHashList使用了散列,使用链表来维护
Set<String> set1 = new HashSet<String>(); Collections.addAll(set1, "A B C D E F G H I J K L".split(" ")); set1.add("M"); print("H: " + set1.contains("H")); print("N: " + set1.contains("N")); Set<String> set2 = new HashSet<String>(); Collections.addAll(set2, "H I J K L".split(" ")); print("set2 in set1: " + set1.containsAll(set2)); set1.remove("H"); print("set1: " + set1); print("set2 in set1: " + set1.containsAll(set2)); set1.removeAll(set2); print("set2 removed from set1: " + set1); Collections.addAll(set1, "X Y Z".split(" ")); print("'X Y Z' added to set1: " + set1); 输出: H: true N: false set2 in set1: true set1: [A, B, C, D, E, F, G, I, J, K, L, M] set2 in set1: false set2 removed from set1: [A, B, C, D, E, F, G, M] 'X Y Z' added to set1: [A, B, C, D, E, F, G, M, X, Y, Z] |
默认情况下TreeSet会按照先大写后小写的顺序去排序,如果想让大小写无关,可以在TreeSet构造器中传入 TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
十.Map
Random rand = new Random(47); Map<Integer,Integer> m = new HashMap<Integer,Integer>(); 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); // put为增加 } System.out.println(m); 输出: {0=481, 1=502, 2=489, 3=508, 4=481, 5=503, 6=519…… |
Map<String,Pet> petMap = new HashMap<String,Pet>(); petMap.put("My Cat", new Cat("Molly")); petMap.put("My Dog", new Dog("Ginger")); petMap.put("My Hamster", new Hamster("Bosco")); print(petMap); Pet dog = petMap.get("My Dog"); // 获取一个element print(dog); print(petMap.containsKey("My Dog")); // 是否包含某个 key print(petMap.containsValue(dog)); // 是否包含某个 value 输出: {My Dog=Dog Ginger, My Cat=Cat Molly, My Hamster=Hamster Bosco} Dog Ginger true true |