什么时候需要使用容器:
可以使用泛型来定于具体容器能够存储的具体类型。List<String> strList = new ArrayList<String>(); // String可以换成其他对象类型。这样给strList中就只能添加String类型的对象。
如果不使用泛型:List list = new ArrayList(); list中可以添加任何类型的对象,但是从list中取出元素的时候,不知道具体类型,代码中需要做向下转型。
java.util包中的Arrays和Collections类中有很多实用的方法,可以在一个Collection中添加一组元素。Arrays.asList()方法接收一个数组或是一个逗号分隔的元素列表,并将其转换成一个List对象。Collections.addAll()方法接收一个Collection对象(参数一),以及一个数组或用一个逗号分隔的列表(参数二),将元素添加到Collection中。也可以使用容器传统的addAll()方法,所有的容器都包含该方法。Collections.addAll()方法很快,所以初始化可以先创建一个空的容器,在调用Collections.addAll()添加元素。
Collection.addAll() (Collection表示具体的一个对象),只能接受一个Collection对象作为参数,没有Collections.addAll()方法灵活。
当把Arrays.asList()的输出当做List时,底层是个数组,不能改变大小,如果添加或者删除元素,运行时会有异常。
Map容器更复杂,初始化只能通过另一个Map。
1 import java.util.ArrayList; 2 import java.util.Arrays; 3 import java.util.Collection; 4 import java.util.Collections; 5 import java.util.List; 6 7 /** 8 * 添加一组元素 9 */ 10 public class AddingGroups { 11 public static void main(String[] args) { 12 Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1, 2, 3)); 13 collection.addAll(Arrays.asList(new Integer[] {4, 5, 6})); 14 Collections.addAll(collection, 7, 8, 9); 15 Collections.addAll(collection, new Integer[] {10, 11, 12}); 16 collection.add(13); 17 List<Integer> list = Arrays.asList(1, 2, 3); 18 list.set(1, 11); 19 // list.add(10); // 运行报错, Arrays.asList()的输出当做list时底层是数组,不能修改其大小 20 } 21 }
两种类型:
常用方法:
方法 | 功能 |
add() | 增加一个元素 |
remove() | 删除一个元素(可以按索引或者引用删除) |
contains() | 判断元素是否在当前的List中 |
get() | 获取指定索引的元素 |
indexOf() | 获取指定元素的索引 |
subList() | 获取列表中的一个片段 |
containsAll() | 判断当前List中是否包含另一个List的所有元素,跟List中元素顺序无关,从示例6-8行可以看出来 |
Collections.sort() | 对容器排序 |
Collections.shuffle() | 随机打乱容器中元素的顺序 |
retainAll() | 取两个List中的交集 |
removeAll() | 从List中删除在参数List中的所有元素 |
set() | 替换指定位置的元素 |
addAll() | 增加一组元素 |
isEmpty() | 判断List是否为空 |
clear() | 清空List |
1 import java.util.ArrayList; 2 import java.util.Collections; 3 import java.util.List; 4 import java.util.Random; 5 6 /** 7 * List常用函数 8 */ 9 public class ListFeatures { 10 public static void main(String[] args) { 11 List<String> strList = new ArrayList<String>(); 12 String[] strs = {"aa", "zz", "yy", "bb", "cc", "xx"}; 13 Collections.addAll(strList, strs); 14 System.out.println("1: " + strList); 15 strList.add("ee"); 16 System.out.println("2: " + strList); 17 System.out.println("3: " + strList.contains("aa")); 18 strList.remove("cc"); 19 System.out.println("4: " + strList); 20 String s = strList.get(2); 21 System.out.println("5: " + s + " " + strList.indexOf(s)); 22 List<String> sub = strList.subList(1, 4); 23 System.out.println("subList: " + sub); 24 System.out.println("6:" + strList.containsAll(sub)); 25 Collections.sort(sub); 26 System.out.println("sorted subList: " + sub); 27 System.out.println("7: " + strList.containsAll(sub)); 28 Collections.shuffle(sub, new Random()); 29 System.out.println("shuffled subList: " + sub); 30 System.out.println("8: " + strList.containsAll(sub)); 31 List<String> copy = new ArrayList<String>(strList); 32 System.out.println("copy: " + copy); 33 copy.retainAll(sub); 34 System.out.println("9: " + copy); 35 copy.set(1, "aa"); 36 System.out.println("10: " + copy); 37 copy.removeAll(sub); 38 System.out.println("11: " + copy); 39 copy.addAll(0, sub); 40 System.out.println("12: " + copy); 41 System.out.println("13: " + copy.isEmpty()); 42 copy.clear(); 43 System.out.println("14: " + copy.isEmpty()); 44 Object[] o = strList.toArray(); 45 System.out.println("15: " + o); 46 String[] ss = strList.toArray(new String[0]); 47 System.out.println("16: " + ss); 48 49 System.out.println(new Dog("mike") == new Dog("mike")); 50 } 51 }
输出: 1: [aa, zz, yy, bb, cc, xx] 2: [aa, zz, yy, bb, cc, xx, ee] 3: true 4: [aa, zz, yy, bb, xx, ee] 5: yy 2 subList: [zz, yy, bb] 6:true sorted subList: [bb, yy, zz] 7: true shuffled subList: [zz, bb, yy] 8: true copy: [aa, zz, bb, yy, xx, ee] 9: [zz, bb, yy] 10: [zz, aa, yy] 11: [aa] 12: [zz, bb, yy, aa] 13: false 14: true 15: [Ljava.lang.Object;@4554617c 16: [Ljava.lang.String;@74a14482
其中remove() ,contains() ,indexOf() ,containsAll() 等涉及比较元素的方法,都会使用equals()比较。但是不同的类equals()的定义可能有所不同。例如:两个String只有在内容完全一样的时候才是等价的。其他引用对象相等,一般都是同一个对象的引用才是相等,内容相同也不是相等。例如:
1 public class Dog { 2 String name; 3 4 public Dog(String name) { 5 this.name = name; 6 } 7 8 public static void main(String[] args) { 9 Dog dog1 = new Dog("Mike"); 10 Dog dog2 = new Dog("Mike"); 11 System.out.println("dog1 == dog2 ? => " + dog1.equals(dog2)); 12 String s1 = "ss"; 13 String s2 = "ss"; 14 System.out.println("s1 == s2 ? => " + s1.equals(s2)); 15 } 16 }
输出: dog1 == dog2 ? => false s1 == s2 ? => true
Java的Iterator只能单向移动,这个Iterator只能用来:
1 import java.util.ArrayList; 2 import java.util.Collection; 3 import java.util.Collections; 4 import java.util.Iterator; 5 6 /** 7 * 迭代器 8 */ 9 public class SimpleIteration { 10 public static void main(String[] args) { 11 Collection<String> collection = new ArrayList<String>(); 12 Collections.addAll(collection, "a", "b", "c", "d"); 13 Iterator<String> it = collection.iterator(); 14 while (it.hasNext()) { 15 System.out.print(it.next() + " "); 16 } 17 System.out.println(); 18 it = collection.iterator(); 19 System.out.println(collection); 20 int size = collection.size(); 21 for (int i = 0; i < size; i++) { 22 it.next(); 23 it.remove(); 24 } 25 System.out.println(collection); 26 } 27 }
输出:
a b c d
[a, b, c, d]
[]
ListIterator是一个更加强大的Iterator的子类型,它只能用于各种List类的访问。在ListIterator中可以双向移动,并可以使用set()方法替换它访问过的最后一个元素。可以使用listIterator()方法产生一个指向List开始的ListIterator,也可以使用listIterator(n)方法创建一个指向索引n的ListIterator。
1 import java.util.ArrayList; 2 import java.util.Collections; 3 import java.util.List; 4 import java.util.ListIterator; 5 6 public class ListIteration { 7 public static void main(String[] args) { 8 List<String> list = new ArrayList<String>(); 9 Collections.addAll(list, "a", "b", "c", "d", "e", "f"); 10 ListIterator<String> it = list.listIterator(); 11 while (it.hasNext()) { 12 System.out.print(it.next() + " "); 13 } 14 System.out.println(); 15 while (it.hasPrevious()) { 16 System.out.print(it.previous() + " "); 17 } 18 System.out.println(); 19 it = list.listIterator(3); 20 while (it.hasNext()) { 21 it.next(); 22 it.set("xx"); 23 } 24 System.out.println(list); 25 } 26 }
输出:
a b c d e f
f e d c b a
[a, b, c, xx, xx, xx]
LinkedList也实现了基本的List的接口,但是它执行某些操作(在List中间插入和移除)比ArrayList更高效,但是在随机访问操作方面却要逊色一些。
常用方法:
方法 | 功能 |
getFirst() | 返回列表的第一个元素,如果List为空,则抛出NoSuchElementException |
element() | 返回列表的第一个元素,如果List为空,则抛出NoSuchElementException |
peek() | 返回列表的第一个元素,如果List为空,返回null |
remove() | 删除并返回列表的第一个元素,如果List为空,则抛出NoSuchElementException |
removeFirst() | 删除并返回列表的第一个元素,如果List为空,则抛出NoSuchElementException |
poll() | 删除并返回列表的第一个元素,如果List为空,返回null |
removeLast() | 删除并返回列表的最后一个元素,如果List为空,则抛出NoSuchElementException |
addFirst() | 在列表头部插入一个元素 |
add() | 在列表尾部插入一个元素 |
addLast() | 在列表尾部插入一个元素 |
offer() | 在列表尾部插入一个元素 |
1 import java.util.Collections;
2 import java.util.LinkedList;
3
4 /**
5 * LinkedList添加删除
6 */
7 public class LinkedListFeatures {
8 public static void main(String[] args) {
9 LinkedList<String> strList = new LinkedList<String>();
10 String str = "abcdefghijklmnopqrstuvwxyz";
11 String[] strs = str.split("");
12 Collections.addAll(strList, strs);
13 System.out.println(strList);
14 System.out.println("getFirst(): " + strList.getFirst());
15 System.out.println("element(): " + strList.element());
16 System.out.println("peek(): " + strList.peek());
17 System.out.println("remove(): " + strList.remove());
18 System.out.println("removeFirst(): " + strList.removeFirst());
19 System.out.println("poll(): " + strList.poll());
20 System.out.println(strList);
21 strList.addFirst("aa");
22 System.out.println("after addFirst(): " + strList);
23 strList.add("bb");
24 System.out.println("after add(): " + strList);
25 strList.addLast("zz");
26 System.out.println("after addLast(): " + strList);
27 strList.offer("yy");
28 System.out.println("after offer(): " + strList);
29 System.out.println("removeLast(): " + strList.removeLast());
30 }
31 }
输出:
[a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]
getFirst(): a
element(): a
peek(): a
remove(): a
removeFirst(): b
poll(): c
[d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]
after addFirst(): [aa, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]
after add(): [aa, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, bb]
after addLast(): [aa, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, bb, zz]
after offer(): [aa, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, bb, zz, yy]
removeLast(): yy
栈,先进先出(LIFO)的容器。LinkedList实现了栈的所有方法,可以直接将LinkedList作为栈使用。
java.util.Stack常用方法:
方法 | 功能 |
push() | 向栈中添加一个元素 |
pop() | 删除并返回栈顶的元素,如果栈为空,抛出EmptyStackException |
peek() | 返回栈顶的元素(不删除),如果栈为空,抛出EmptyStackException |
isEmpty() | 判断栈是否为空 |
注意Stack和LinkedList的pop()、peek()方法不太相同。
1 import java.util.LinkedList;
2 import java.util.Stack;
3
4 /**
5 * Stack 和 LinkedList
6 */
7 public class StackCollision {
8 public static void main(String[] args) {
9 System.out.println("This is Stack");
10 Stack<String> stack = new Stack<String>();
11 stack.push("a");
12 stack.push("b");
13 stack.push("c");
14 System.out.println("Stack is Empty: " + stack.isEmpty());
15 System.out.println(stack.pop());
16 System.out.println(stack.peek());
17 System.out.println(stack.pop());
18 System.out.println(stack.pop());
19 System.out.println("Stack is Empty: " + stack.isEmpty());
20 // System.out.println(stack.pop()); // 栈为空时,抛出EmptyStackException
21 // System.out.println(stack.peek()); // 栈为空时,抛出EmptyStackException
22 System.out.println("This is LinkedList");
23 LinkedList<String> linkedList = new LinkedList<String>();
24 linkedList.push("a");
25 linkedList.push("b");
26 linkedList.push("c");
27 System.out.println(linkedList.pop());
28 System.out.println(linkedList.peek());
29 System.out.println(linkedList.pop());
30 System.out.println(linkedList.pop());
31 System.out.println(linkedList.peek());
32 }
33 }
输出:
This is Stack
Stack is Empty: false
c
b
b
a
Stack is Empty: true
This is LinkedList
c
b
b
a
null
队列是一个典型的先进先出(FIFO)的容器。队列常被当做一种可靠地对象将程序的某个区域传输到另一个区域的途径。队列在并发编程中特别重要。
LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以作为Queue的一种实现。
常见方法:
offer(), peek(),element(),poll(),remove(),参见LinkedList中方法说明。
1 import java.util.LinkedList;
2 import java.util.Queue;
3
4 public class QueueDemo {
5 public static void printQ(Queue queue) {
6 while (queue.peek() != null) {
7 System.out.print(queue.remove() + " ");
8 }
9 System.out.println();
10 }
11
12 public static void main(String[] args) {
13 Queue<Character> qc = new LinkedList<Character>();
14 for (char c : "Hello World".toCharArray()) {
15 qc.offer(c);
16 }
17 printQ(qc);
18 }
19 }
输出:
H e l l o W o r l d
优先级队列(PriorityQueue)声明下一个弹出元素时最需要的元素(具有最高的优先级)。当在PriorityQueue上调用offer()方法插入一个对象时,这个对象在队列中会被排序,默认是自然顺序(一般都是字典顺序),但是可以通过提供自己的Comparator来修改这个顺序。
1 import java.util.Arrays;
2 import java.util.Collections;
3 import java.util.List;
4 import java.util.PriorityQueue;
5
6 public class PriorityQueueDemo {
7 public static void main(String[] args) {
8 List<Integer> ints = Arrays.asList(25, 22, 20, 18, 14, 9, 3, 1, 1, 2, 23, 25);
9 PriorityQueue<Integer> priorityIntQueue = new PriorityQueue<Integer>(ints);
10 PriorityQueue<Integer> reverseIntPriorityQueue =
11 new PriorityQueue<Integer>(ints.size(), Collections.reverseOrder());
12 reverseIntPriorityQueue.addAll(ints);
13 QueueDemo.printQ(priorityIntQueue);
14 QueueDemo.printQ(reverseIntPriorityQueue);
15
16 List<String> strs = Arrays.asList("apple", "Banana", "Pear", "orange", "litchi", "pineapple", "Mango");
17 PriorityQueue<String> priorityStrQueue = new PriorityQueue<String>(strs);
18 PriorityQueue<String> reverseStrPriorityQueue = new PriorityQueue<String>(Collections.reverseOrder());
19 reverseStrPriorityQueue.addAll(strs);
20 QueueDemo.printQ(priorityStrQueue);
21 QueueDemo.printQ(reverseStrPriorityQueue);
22 }
23 }
输出:
1 1 2 3 9 14 18 20 22 23 25 25
25 25 23 22 20 18 14 9 3 2 1 1
Banana Mango Pear apple litchi orange pineapple
pineapple orange litchi apple Pear Mango Banana
可以看到,默认情况下最小值拥有最高的优先级。可通过提供自己的Comparator对象来改变排序,我们使用了Collections.reverseOrder()来产生反序的Comparator(当然你也可以自己写一个)。
Set不保存重复的元素,常用于测试归属性,很容易判断某个对象是否在某个Set中,使用contains()方法。Set和Collection有完全一样的接口,没有任何额外的功能,只是方法的实现不同。
查找时常用HashSet,它专门对快速查找进行了优化。HashSet存储时没有顺序(或者说你不知道什么情况下才进行了排序),如果想用有序,可以使用TreeSet(按字典排序)或LinkedHashSet(按插入顺序排序)。
1 import java.util.HashSet;
2 import java.util.LinkedHashSet;
3 import java.util.Random;
4 import java.util.Set;
5 import java.util.TreeSet;
6
7 public class SetOfInteger {
8 public static void main(String[] args) {
9 Random rand = new Random(47);
10 Set<Integer> hashSet = new HashSet<Integer>();
11 Set<Integer> treeSet = new TreeSet<Integer>();
12 Set<Integer> linkedHashSet = new LinkedHashSet<Integer>();
13 System.out.print("第一次插入的元素:");
14 for (int i = 0; i < 10; i++) {
15 int num = rand.nextInt(30);
16 System.out.print(num + " ");
17 hashSet.add(num);
18 treeSet.add(num);
19 linkedHashSet.add(num);
20 }
21 System.out.println();
22 System.out.println("HashSet: " + hashSet);
23 System.out.println("TreeSet: " + treeSet);
24 System.out.println("LinkedHashSet: " + linkedHashSet);
25 for (int i = 0; i < 10000; i++) {
26 int num = rand.nextInt(30);
27 hashSet.add(num);
28 treeSet.add(num);
29 linkedHashSet.add(num);
30 }
31 System.out.println("hashSet: " + hashSet);
32 System.out.println("treeSet: " + treeSet);
33 System.out.println("LinkedHashSet: " + linkedHashSet);
34 System.out.println("Set include 1: " + hashSet.contains(1));
35 }
36 }
输出:
第一次插入的元素:8 5 13 11 1 29 28 20 12 7
HashSet: [1, 20, 5, 7, 8, 11, 28, 12, 13, 29]
TreeSet: [1, 5, 7, 8, 11, 12, 13, 20, 28, 29]
LinkedHashSet: [8, 5, 13, 11, 1, 29, 28, 20, 12, 7]
hashSet: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
treeSet: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
LinkedHashSet: [8, 5, 13, 11, 1, 29, 28, 20, 12, 7, 18, 21, 19, 16, 0, 14, 3, 26, 25, 10, 2, 24, 4, 6, 22, 27, 17, 9, 23, 15]
Set include 1: true
Map可以将对象映射到其他对象。
常用方法:
方法 | 功能 |
put() | 向Map中添加一个键值对的元素 |
get() | 获取键对应的值,如果键不在容器中,返回null |
containsKey() | 判断键是否在Map中 |
containsValue() | 判断值是否在Map中 |
keySet() | 获取键的Set集合,常用于遍历Map |
entrySet() | 返回键-值的一组对象,该对象可使用getKey(),getValue()获取对应的键和值,常用于遍历Map |
remove() | 删除指定的键值对元素 |
1 import java.util.HashMap;
2 import java.util.Map;
3
4 public class DogMap {
5 public static void main(String[] args) {
6 Map<String, Dog> dogMap = new HashMap<String, Dog>();
7 dogMap.put("Jack", new Dog("Jack"));
8 dogMap.put("Harry", new Dog("Harry"));
9 dogMap.put("An", new Dog("An"));
10 System.out.println(dogMap);
11 Dog jack = dogMap.get("Jack");
12 System.out.println(jack);
13 System.out.println(dogMap.containsKey("Jack"));
14 System.out.println(dogMap.containsValue(jack));
15 // 使用keySet遍历
16 for (String dogName : dogMap.keySet()) {
17 System.out.println(dogName + " = " + dogMap.get(dogName));
18 }
19 // 使用entrySet遍历
20 for (Map.Entry<String, Dog> entry : dogMap.entrySet()) {
21 System.out.println(entry.getKey() + " = " + entry.getValue());
22 }
23 dogMap.remove("Jack");
24 System.out.println(dogMap);
25 }
26 }
输出:
{Harry=Harry, Jack=Jack, An=An}
Jack
true
true
Harry = Harry
Jack = Jack
An = An
Harry = Harry
Jack = Jack
An = An
{Harry=Harry, An=An}
Collection是描述所有序列容器共性的根接口。AbstractCollection类提供了Collection的默认实现,使得你可以创建AbstractCollection的子类型,而只实现其中iterator()和size()方法。
1 import java.util.Arrays;
2 import java.util.Collection;
3 import java.util.Iterator;
4 import java.util.List;
5
6 public class InterfaceVsIterator {
7 public static void display(Iterator<String> it) {
8 while (it.hasNext()) {
9 System.out.print(it.next() + " ");
10 }
11 System.out.println();
12 }
13
14 public static void display(Collection<String> strs) {
15 for (String s : strs) {
16 System.out.print(s + " ");
17 }
18 System.out.println();
19 }
20
21 public static void main(String[] args) {
22 List<String> stringList = Arrays.asList("aa", "bb", "cc", "dd");
23 display(stringList.iterator());
24 display(stringList);
25 }
26 }
输出:
aa bb cc dd
aa bb cc dd
两个版本的display都可以生效,而且Collection更方便,因为他是Iterable类型(下面会讲),因此可以直接使用foreach结构。
当要实现一个不是Collection的外部类时,要它实现Collection接口非常困难(因为你要实现Collection所有的方法)。使用Iterator就会很方便,例如:
1 import java.util.Iterator;
2
3 class StringSequence {
4 protected String[] strs = {"aa", "bb", "cc"};
5 }
6
7 public class NonCollectionSequence extends StringSequence {
8 public Iterator<String> iterator() {
9 return new Iterator<String>() {
10 private int index = 0;
11
12 @Override
13 public boolean hasNext() {
14 return index < strs.length;
15 }
16
17 @Override
18 public String next() {
19 return strs[index++];
20 }
21 };
22 }
23
24 public static void main(String[] args) {
25 NonCollectionSequence nc = new NonCollectionSequence();
26 InterfaceVsIterator.display(nc.iterator());
27 }
28 }
输出:
aa bb cc
foreach语法可以应用于任何的Collection对象,实际上是因为实现了Iterable接口,该接口包含一个能够产生Iterator的iterator()方法,并且Iterable接口被foreach用来在序列中移动。
foreach也可用于数组,但是实际上数组并不是一个Iterable。
1 import java.util.Iterator;
2
3 public class IterableClass implements Iterable<String> {
4 private String[] words = "Hello World, this is a class that implements Iterable.".split(" ");
5
6 @Override
7 public Iterator<String> iterator() {
8 return new Iterator<String>() {
9 private int index = 0;
10
11 @Override
12 public boolean hasNext() {
13 return index < words.length;
14 }
15
16 @Override
17 public String next() {
18 return words[index++];
19 }
20 };
21 }
22
23 public static void main(String[] args) {
24 for (String s : new IterableClass()) {
25 System.out.print(s + " ");
26 }
27 }
28 }
输出:
Hello World, this is a class that implements Iterable.
Java提供了大量持有对象的方式:
原文:https://www.cnblogs.com/songchj-bear/p/10662832.html