轉載:http://www.cnblogs.com/hzmark/archive/2012/12/17/CollectionBase.html html
數組是一種很常見的數據結構,開始接觸編程的時候多數程序都和數組相關。剛開始接觸Java時也是一直使用數組寫一些程序,後來愈來愈以爲數組這東西無法知足需求了,這時一位「前輩」對我說了一句:不會用集合類就等於沒學過Java。而後才知道有集合類。java
想一想已是三、4年前的事了,時間如白駒過隙啊。編程
何時數組會顯得力不從心,無法知足需求,須要集合類呢?數組
固然,上面的狀況不是絕對的,只是數組比較難知足。這時集合類(也可稱爲容器類)就顯示了它強大的功能。安全
集合類的分類(圖片轉自http://biancheng.dnbcw.info/1000wen/359774.html)數據結構
上圖中不包含Queue內容,部分Map的實現類未給出。ide
常見使用的有List、Set、Map及他們的實現類。函數
List、Set、Map接口及各實現類的特性spa
接口設計 |
特性 |
實現類 |
實現類特性 |
成員要求 |
List |
線性、有序的存儲容器,可經過索引訪問元素 |
ArrayList |
數組實現。非同步。 |
|
Vector |
相似ArrayList,同步。 |
|
||
LinkedList |
雙向鏈表。非同步。 |
|
||
Map |
保存鍵值對成員 |
HashMap |
基於哈希表的 Map 接口的實現,知足通用需求 |
任意Object對象,若是修改了equals方法,需同時修改hashCode方法 |
TreeMap |
默認根據天然順序進行排序,或者根據建立映射時提供的Comparator進行排序 |
鍵成員要求實現caparable接口,或者使用Comparator構造TreeMap。鍵成員通常爲同一類型。 |
||
LinkedHashMap |
相似於HashMap,但迭代遍歷時取得「鍵值對」的順序是其插入順序或者最近最少使用的次序 |
與HashMap相同 |
||
IdentityHashMap |
使用==取代equals()對「鍵值」進行比較的散列映射 |
成員經過==判斷是否相等 |
||
WeakHashMap |
弱鍵映射,容許釋放映射所指向的對象 |
|
||
ConcurrentHashMap |
線性安全的Map |
|
||
Set |
成員不能重複 |
HashSet |
爲快速查找設計的Set |
元素必須定義hashCode() |
TreeSet |
保持次序的Set,底層爲樹結構 |
元素必須實現Comparable接口 |
||
LinkedHashSet |
內部使用鏈表維護元素的順序(插入的次序) |
元素必須定義hashCode() |
在知足要求的狀況下,Map應儘可能使用HashMap,Set應儘可能使用HashSet。
集合類的基本使用
List
- List基本操做
- ArrayList<String> arrayList = new ArrayList<String>();
- arrayList.add("Tom");
- arrayList.add("Jerry");
- arrayList.add("Micky");
- // 使用Iterator遍歷元素
- Iterator<String> it = arrayList.iterator();
- while (it.hasNext()) {
- String str = it.next();
- System.out.println(str);
- }
- // 在指定位置插入元素
- arrayList.add(2, "Kate");
- // 經過索引直接訪問元素
- for (int i = 0; i < arrayList.size(); i++) {
- System.out.println(arrayList.get(i));
- }
- List<String> subList = new ArrayList<String>();
- subList.add("Mike");
- // addAll(Collection<? extends String> c)添加所給集合中的全部元素
- arrayList.addAll(subList);
- // 判斷是否包含某個元素
- if (arrayList.contains("Mike")) {
- System.out.println("Mike is include in the list");
- }
- LinkedList<String> linkedList = new LinkedList<String>();
- linkedList.addAll(arrayList);
- // 獲取指定元素
- System.out.println(linkedList.get(4));
- // 獲取第一個元素
- System.out.println(linkedList.getFirst());
- // 獲取最後一個元素
- System.out.println(linkedList.getLast());
- // 獲取並刪除第一個元素
- System.out.println(linkedList.pollFirst());
- // 獲取,但不移除第一個元素
- System.out.println(linkedList.peekFirst());
ArrayList和LinkedList的效率比較
- ArrayList添加元素的效率
- ArrayList<String> arrList = new ArrayList<String>();
- long startTimeMillis, endTimeMillis;
- startTimeMillis = System.currentTimeMillis();
- for (int i = 0; i < 10000; i++) {
- arrList.add(0, "addString");
- }
- endTimeMillis = System.currentTimeMillis();
- System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
- + "ms");
- arrList.clear();
- startTimeMillis = System.currentTimeMillis();
- for (int i = 0; i < 20000; i++) {
- arrList.add(0, "addString");
- }
- endTimeMillis = System.currentTimeMillis();
- System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
- + "ms");
- arrList.clear();
- startTimeMillis = System.currentTimeMillis();
- for (int i = 0; i < 40000; i++) {
- arrList.add(0, "addString");
- }
- endTimeMillis = System.currentTimeMillis();
- System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
- + "ms");
- arrList.clear();
- startTimeMillis = System.currentTimeMillis();
- for (int i = 0; i < 80000; i++) {
- arrList.add(0, "addString");
- }
- endTimeMillis = System.currentTimeMillis();
- System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
- + "ms");
- arrList.clear();
- startTimeMillis = System.currentTimeMillis();
- for (int i = 0; i < 160000; i++) {
- arrList.add(0, "addString");
- }
- endTimeMillis = System.currentTimeMillis();
- System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
- + "ms");
- arrList.clear();
- startTimeMillis = System.currentTimeMillis();
- for (int i = 0; i < 320000; i++) {
- arrList.add(0, "addString");
- }
- endTimeMillis = System.currentTimeMillis();
- System.out.println("ArrayList:" + (endTimeMillis - startTimeMillis)
- + "ms");
執行時
- Set基礎操做
- List<Integer> list = new ArrayList<Integer>();
- list.add(3);
- list.add(4);
- HashSet<Integer> hashSet = new HashSet<Integer>();
- hashSet.add(1);
- hashSet.add(3);
- hashSet.add(2);
- hashSet.add(6);
- // 重複元素將不能被添加
- hashSet.add(3);
- // 只要有元素被添加就返回true
- if (hashSet.addAll(list)) {
- System.out.println("Add success");
- }
- // 判斷是否存在某個集合
- if (hashSet.containsAll(list)) {
- System.out.println("The hashSet is contain 3 and 4");
- }
- Iterator<Integer> it = hashSet.iterator();
- while (it.hasNext()) {
- System.out.print(it.next() + " ");
- // 1 2 3 4 6
- // 看結果是被排序了,HashSet按照Hash函數排序,Integer值的HashCode就是其int值
- }
- // 換轉成數組
- Object[] integers = hashSet.toArray();
- for (int i = 0; i < integers.length; i++) {
- System.out.print((Integer) integers[i]);
- }
- //移除元素
- hashSet.remove(3);
- TreeSet<String> treeSet = new TreeSet<String>();
- treeSet.add("C");
- treeSet.add("A");
- treeSet.add("D");
- treeSet.add("B");
- for (Iterator<String> strIt = treeSet.iterator(); strIt.hasNext();) {
- System.out.print(strIt.next());
- // ABCD 按照字母順序
- }
- LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
- linkedHashSet.add("C");
- linkedHashSet.add("A");
- linkedHashSet.add("D");
- linkedHashSet.add("B");
- for (Iterator<String> linkedIt = linkedHashSet.iterator(); linkedIt
- .hasNext();) {
- System.out.print(linkedIt.next());
- // CADB 按照插入順序
- }
間比較
執行次數(在0號位置插入) |
ArrayList所用時間(ms) |
LinkedList所用時間(ms) |
10000 |
31 |
0 |
20000 |
141 |
0 |
40000 |
484 |
16 |
80000 |
1985 |
0 |
160000 |
7906 |
0 |
320000 |
31719 |
16 |
執行次數(在尾部插入) |
ArrayList所用時間(ms) |
LinkedList所用時間(ms) |
10000 |
0 |
0 |
20000 |
15 |
0 |
40000 |
0 |
0 |
80000 |
0 |
0 |
160000 |
0 |
15 |
320000 |
0 |
16 |
循環輸出次數(get(index)方法) |
ArrayList所用時間(ms) |
LinkedList所用時間(ms) |
10000 |
93 |
204 |
20000 |
188 |
797 |
40000 |
328 |
2734 |
80000 |
688 |
13328 |
160000 |
1594 |
62313 |
320000 |
2765 |
過久了…… |
由於ArrayList底層由數組實現,在0號位置插入時將移動list的全部元素,在末尾插入元素時不須要移動。LinkedList是雙向鏈表,在任意位置插入元素所需時間均相同。因此在List中有較多插入和刪除操做的狀況下應使用LinkedList來提升效率,而有較多索引查詢的時候使用ArrayList(使用加強型的for循環或Iterator遍歷LinkedList效率將提升不少)。
Map
- Map基本操做
- HashMap<String, Integer> map = new HashMap<String, Integer>();
- // 向Map中添加元素
- map.put("Tom", 26);
- map.put("Jack", 18);
- map.put("Micky", 17);
- map.put("Kate", 15);
- // 根據Key獲取Value
- System.out.println("Jack is " + map.get("Jack") + " years old");
- // 移除
- map.remove("Micky");
- // 遍歷Map
- for (Entry<String, Integer> entry : map.entrySet()) {
- System.out.println("name:" + entry.getKey() + " age:"
- + entry.getValue());
- }
- // Key相同的元素將被覆蓋
- map.put("Jack", 19);
- // 根據Key獲取Value
- System.out.println("Jack is " + map.get("Jack") + " years old");
- // 判斷是否包含某個Key
- if (map.containsKey("Tom")) {
- System.out.println(map.get("Tom"));
- }
- // 判斷是否包含某個Value
- if (map.containsValue(26)) {
- System.out.println("The map include the value 26");
- }
- // 判斷map是否爲空
- if (!map.isEmpty()) {
- // 獲取map大小
- System.out.println("The map's size=" + map.size());
- }
- // 獲取Key的集合
- for (String str : map.keySet()) {
- System.out.println(str);
- }
- TreeMap<String, Integer> treeMap = new TreeMap<String, Integer>();
- treeMap.putAll(map);
- // 輸出內容按照key值排序
- for (Entry<String, Integer> entry : treeMap.entrySet()) {
- System.out.println("name:" + entry.getKey() + " age:"
- + entry.getValue());
- // name:Jack age:19
- // name:Kate age:15
- // name:Tom age:26
- }
- LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<String, Integer>();
- // 向Map中添加元素
- linkedHashMap.put("Tom", 26);
- linkedHashMap.put("Jack", 18);
- linkedHashMap.put("Micky", 17);
- linkedHashMap.put("Kate", 15);
- // 保持了插入的順序
- for (Entry<String, Integer> entry : linkedHashMap.entrySet()) {
- System.out.println("name:" + entry.getKey() + " age:"
- + entry.getValue());
- // name:Tom age:26
- // name:Jack age:18
- // name:Micky age:17
- // name:Kate age:15
- }
Set