11.持有对象
1.泛型和类型安全的容器
- 编译器将不允许你向容器里插入不正确的类型。
2.基本概念
- Collection 一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序。
- Map一组成对的“键值对”对象,允许你使用键来查找值。
public class SimpleCollection {
public static void main(String[] args) {
Collection<Integer> c = new ArrayList<Integer>();
for(int i = 0; i < 10; I++)
c.add(i); // Autoboxing
for(Integer i : c)
System.out.print(i + ", ");
}
} /* Output:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
*///:~
3.添加一组元素
Arrays.asList()方法接受一个数组或是一个用逗号隔开分隔的元素列表,并将其转换为一个List对象。Collections.addAll()方法接受一个Collection对象,以及一个数组或用逗号分隔的列表,将其添加到Collection中。
class Snow {}
class Crusty extends Snow {}
class Slush extends Snow {}
class Powder extends Snow {}
class Light extends Powder {}
class Heavy extends Powder {}
public class AsListInference {
public static void main(String[] args) {
List<Snow> snow1 = Arrays.asList(
new Crusty(), new Slush(), new Powder());
// Won't compile: 当Arrays.asList里都是Powder类时,声明为List<Powder>
// List<Snow> snow2 = Arrays.asList(
// new Light(), new Heavy());
// Compiler says:
// found : java.util.List<Powder>
// required: java.util.List<Snow>
// Collections.addAll() doesn't get confused:
List<Snow> snow3 = new ArrayList<Snow>();
Collections.addAll(snow3, new Light(), new Heavy());
// Give a hint using an
// explicit type argument specification:
List<Snow> snow4 = Arrays.<Snow>asList(
new Light(), new Heavy());
}
} ///:~
public class AddingGroups {
public static void main(String[] args) {
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));
// 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<Integer> 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.
}
} ///:~
4.容器的打印
Collection每个槽中只保存一个元素
- List 以特定顺序保存一组对象
- Set 元素不能重复
HashSet是最快的获取元素方式。如果存储顺序很重要,那么可以使用TreeSet,它按照比较结果的升序保存对象,或者使用LinkedHashSet,它按照被添加的顺序保存对象。 - Queue 只允许在容器的一端插入对象,并从另一端移除对象
- map在每个槽找那个保存两个对象,即键与值;
同理,HashMap是最快的获取元素方式,如果存储顺序很重要,使用TreeMap,它按照比较结果的升序保存对象,或者使用LinkedHashSet,它按照被添加的顺序保存对象。
public class PrintingContainers {
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>()));
}
} /* 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}
*///:~
5. List
List承诺可以将元素维护在特定的序列中。
ArrayList
- 以数组实现。节约控件,但数组容量有限制。超出限制会增加50%容量。默认第一次插入元素时创建大小为10的数组。
- 按数组下标访问元素 get set方法的性能更高,这是数组的基本优势
- 直接在数组末尾加入元素 -add()的性能也高,但如果按照下标插入add(),删除remove(),则要用System.arraycopy()来移动部分受影响的元素(角标会发生变化),这是基本劣势
public static void main(String[] args) {
Random rand = new Random(47);
List<String> pp = Arrays.asList("abc", "bcd", "cde", "def");
List<String> pets = new ArrayList<>(pp);
print("1: " + pets);
String p = pets.get(2);
print("4: " + p + " " + pets.indexOf(p));
String cymric = new String();
print("5: " + pets.indexOf(cymric));
print("6: " + pets.remove(cymric));
// Must be the exact object:
print("7: " + pets.remove(p));
print("8: " + pets);
pets.add(3, new String("efg")); // Insert at an index
print("9: " + pets);
List<String> sub = pets.subList(1, 4);
print("subList: " + sub);
print("10: " + pets.containsAll(sub));
Collections.sort(sub); // In-place sort
print("sorted subList: " + sub);
// Order is not important in containsAll():
print("11: " + pets.containsAll(sub));
Collections.shuffle(sub, rand); // Mix it up
print("shuffled subList: " + sub);
print("12: " + pets.containsAll(sub));
List<String> copy = new ArrayList<String>(pets);
sub = Arrays.asList(pets.get(1), pets.get(4));
print("sub: " + sub);
copy.retainAll(sub);
print("13: " + copy);
copy = new ArrayList<String>(pets); // Get a fresh copy
copy.remove(2); // Remove by index
print("14: " + copy);
copy.removeAll(sub); // Only removes exact objects
print("15: " + copy);
copy.set(1, new String()); // Replace an element
print("16: " + copy);
copy.addAll(2, sub); // Insert a list in the middle
print("17: " + copy);
print("18: " + pets.isEmpty());
pets.clear(); // Remove all elements
print("19: " + pets);
print("20: " + pets.isEmpty());
print("21: " + pets);
Object[] o = pets.toArray();
}
6.迭代器
迭代器能够将遍历序列的操作与序列底层的结构分离。正由于此,我们常说迭代器统一了对容器的访问方式。
public static void main(String[] args) {
List<String> pp = Arrays.asList("admin", "what this", "spaces", "feature","uimian","who that",
"nonoN");
List<String> pets = new ArrayList<>(pp);
Iterator<String> it = pets.iterator();
while (it.hasNext()) {
String p = it.next();
System.out.print("" + p + " ");
}
System.out.println();
// A simpler approach, when possible:
for (String p : pets)
System.out.print("" + p + " ");
System.out.println();
// An Iterator can also remove elements:
it = pets.iterator();
for (int i = 0; i < 6; i++) {
it.next();
it.remove();
}
System.out.println(pets);
}
ListIterator是一个更加强大的Iterator的子类型,它只能用于各种list类的访问。尽管Iterator只能向前移动,但是ListIterator可以双向移动。
public static void main(String[] args) {
List<String> pp = Arrays.asList("admin", "what this", "spaces", "feature", "uimian", "who that",
"nonoN", "open");
List<String> pets = new ArrayList<>(pp);
ListIterator<String> 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() + "- ");
}
System.out.println();
System.out.println(pets);
it = pets.listIterator(3);
while (it.hasNext()) {
it.next();
it.set("");
}
System.out.println(pets);
}
7. LinkedList
以双向链表实现。链表无容量限制,但双向链表本身使用了更多控件,也需要额外的链表指针操作。按下标访问元素—get(i)/set(i,e) 要悲剧的遍历链表将指针移动到位(如果i>数组大小的一半,会从末尾移起)。
LinkedList是一个简单的数据结构,与ArrayList不同的是,他是基于链表实现的。
public static void main(String[] args) {
List<String> pp = Arrays.asList("admin", "what this", "spaces", "feature","uimian","who that",
"nonoN");
LinkedList<String> pets =
new LinkedList<>(pp);
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 String("miandiin"));
print("After addFirst(): " + pets);
print("After offer(): " + pets);
print("After add(): " + pets);
pets.addLast(new String("andiin"));
print("After addLast(): " + pets);
print("pets.removeLast(): " + pets.removeLast());
}
8.Set
Set不保存重复的元素。
public static void main(String[] args) {
Set<String> set1 = new HashSet<String>();
Collections.addAll(set1,
"A B C D E F G h 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 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);
}
9.Map
Map是一种将对象映射到其他对象的能力
HashMap
HashMap是基于Map接口的实现,存储键值对时,它可以接收null的键值,是非同步的,HashMap存储着Entry(hash,key,value,next)对象。
***LinkedHashMap
LinkedHashMap是Hash表和链表的实现,并且依靠着双向链表保证了迭代顺序是插入的顺序。
public static Map<String, List<String>>
petPeople = new HashMap<String, List<String>>();
static {
petPeople.put(new String("Dawn"),
Arrays.asList(new String("Molly"),new String("Spot")));
petPeople.put(new String("Kate"),
Arrays.asList(new String("Shackleton"),
new String("Elsie May"), new String("Margrett")));
petPeople.put(new String("Marilyn"),
Arrays.asList(
new String("Louie aka Louis Snorkelstein Dupree"),
new String("Stanford aka Stinky el Negro"),
new String("Pinkola")));
petPeople.put(new String("Luke"),
Arrays.asList(new String("Fuzzy"), new String("Fizzy")));
petPeople.put(new String("Isaac"),
Arrays.asList(new String("Freckly")));
}
public static void main(String[] args) {
print("People: " + petPeople.keySet());
print("Pets: " + petPeople.values());
for(String person : petPeople.keySet()) {
print(person + " has:");
for(String pet : petPeople.get(person))
print(" " + pet);
}
}
} /* Output:
People: [Person Luke, Person Marilyn, Person Isaac, Person Dawn, Person Kate]
Pets: [[Rat Fuzzy, Rat Fizzy], [Pug Louie aka Louis Snorkelstein Dupree, Cat Stanford aka Stinky el Negro, Cat Pinkola], [Rat Freckly], [Cymric Molly, Mutt Spot], [Cat Shackleton, Cat Elsie May, Dog Margrett]]
Person Luke has:
Rat Fuzzy
Rat Fizzy
Person Marilyn has:
Pug Louie aka Louis Snorkelstein Dupree
Cat Stanford aka Stinky el Negro
Cat Pinkola
Person Isaac has:
Rat Freckly
Person Dawn has:
Cymric Molly
Mutt Spot
Person Kate has:
Cat Shackleton
Cat Elsie May
Dog Margrett
*///:~
10.Queue
队列是一个典型的先进先出的容器。即从容器的一端放入事物,从另一端取出,并且事物放入容器的顺序与取出的顺序是相同的。子弹头儿原理。
- offer()方法是与Queue相关的方法之一,它在允许的情况下,将一个元素插入到队尾,或者返回false
- peek()和element()都将在不移除的情况下返回队头,但peek()方法在队列为空时返回null,而element()会抛出NoSuchElementException异常。
- poll()和remove()方法将移除并返回队头,但poll在队列为空时返回null,而remove()会抛出NoSuchElementException。
public class QueueDemo {
public static void printQ(Queue queue) {
while(queue.peek() != null)
System.out.print(queue.remove() + " ");
System.out.println();
}
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<Integer>();
Random rand = new Random(47);
for(int i = 0; i < 10; i++){
System.out.println(rand.nextInt(i + 10));
queue.offer(rand.nextInt(i + 10));
// boolean offer = queue.offer(i);
}
printQ(queue);
Queue<Character> qc = new LinkedList<Character>();
for(char c : "Brontosaurus".toCharArray())
qc.offer(c);
printQ(qc);
}
} /* Output:
8 1 1 1 5 14 3 1 0 1
B r o n t o s a u r u s
*///:~
10.Collection和Iterator
Collection是描述所有序列容器的共性的根接口,它可能被认为是一个附属接口,即因为要表示其他若干个接口的共性而出现的接口。
public class CollectionSequence extends AbstractCollection<String> {
private String[] pets = new String[]{"b", "c", "a", "d", "g", "e", "f", "h"};
@NonNull
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int index = 0;
public boolean hasNext() {
return index < pets.length;
}
public String next() {
return pets[index++];
}
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
public int size() {
return pets.length;
}
public static void main(String[] args) {
CollectionSequence c = new CollectionSequence();
InterfaceVsIterator.display(c);
InterfaceVsIterator.display(c.iterator());
}
} /* Output:
0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx
0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx
*///:~
11.Foreach与迭代器
public class IterableClass implements Iterable<String> {
protected String[] words = ("And that is how " +
"we know the Earth to be banana-shaped.").split(" ");
public Iterator<String> iterator() {
return new Iterator<String>() {
private int index = 0;
public boolean hasNext() {
return index < words.length;
}
public String next() { return words[index++]; }
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
public static void main(String[] args) {
for(String s : new IterableClass())
System.out.print(s + " ");
}
} /* Output:
And that is how we know the Earth to be banana-shaped.
*///:~
到这里持有对象就告一段落了,大部分粘贴出的是编程思想里的案例,也比较方便复习。