Java_集合框架

編程時,經常須要集中存放多個數據。能夠使用數組來保存,但一旦初始化時指定了數組的長度,數組就不可變了。而集合類就很好的解決了這一問題。Java集合大體可分爲 Set、List、Queue、Map四種體系。Java集合框架圖:

【簡圖】
java

  • Set 不可重複集合 {HashSet, TreeSet}
  • List 有序,重複集合 {ArrayList, LinkedList, Vector}
  • Map 具備映射關係 key-value集合 {HashMap, TreeMap, HashTable}
  • Queue、Deue 隊列集合 {PriorityQueue, ArrayDeue}

注:順序分爲 天然排序[a-z], 添加元素的排序shell

1、Collection 和 迭代器

Collection接口是 List、Set和 Queue 接口的父接口編程

  • 迭代器 Iterator 和 Enumeration

迭代器: Enumeration<E> 接口被 Iterator <E>替代。它的實現類StringTokenizer數組

Enumeration e  = new StringTokenizer("A-B-C","-");
while(e.hasMoreElements()){ // 是否還有元素
    System.out.println(e.nextElement());  //返回下一個元素
}

// Arrays.asList(T...a)返回的是一個T List<T> 類型的new ArrayList<>(a)對象
// 這個ArrayList<E> 是定義在Arrays中的私有類部類,且有一個帶 E[] a 參數
Collection c = Arrays.asList("a","n","b");
Iterator it = c.iterator();
for( ;it.hasNext();)
    System.out.println(it.next());
  • ListIterator 接口
    • 容許雙向遍歷list
    • 在遍歷時修改List元素
    • 遍歷時獲取迭代器當前遊標所在位置
List l = Arrays.asList("a","n","b");
ListIterator lit = l.listIterator();
while(lit.hasNext()){
    System.out.println(lit.next());
}
while(lit.hasPrevious()){
    System.out.println(lit.previous());
}
// foreach 是經過迭代器來實現
for (Object aL : l) {
    System.out.println(aL);
}

2、List 接口與實現類

  • List
    List是一個有序可重複的集合,經常使用的List實現類 ArrayList, LinkedList和Vector。List接口實現類在實現插入元素時,都會根據索引進行排列,會改變其餘元素的位置。安全

  • AbstractList
    繼承 AbstractCollection 抽象類,實現了 List 接口 ,是 ArrayList 和 AbstractSequentiaList 的父類。AbstractList 內部已經提供了 Iterator, ListIterator 迭代器的實現類Itr ,ListItr。多線程

  • ArrayList、LinkedList、Vectororacle

1-- ArrayList 使用數組方式存儲數據(本質上是一個數組),y有初始容量大小 ,超容時自動擴容爲原來的1.5倍。線程是不安全的。增刪效率低,查詢效率高。
防止不一樣步訪問列表:List list = Collections.synchronizedList(new ArrayList(...));框架

ArrayList<String> al = new ArrayList<String>(5); //指定容量大小
al.ensureCapacity(10); // 增長容量
al.add("Hello"); // 元素可重複
al.add("Hello");
al.add("word");
al.set(1, "Two"); // 替換索引爲1 的元素
al.add("four");
al.trimToSize();
al.remove(3); // 刪除索引爲 3 的元素
System.out.println(al.toArray().length);
System.out.println(al.size()); //3 元素個數
System.out.println(al.get(1)); //Two 獲取 index=0 的元素
//System.out.println(al.get(3)); // index=3 的元素被刪除,報錯

2-- LinkedList雙向鏈表,實現了List和 Deque接口。與ArrayList同樣也是線程不安全。雙向鏈表,不存在元素限制,沒有擴容機制。其查詢效率差,增刪效率高。dom

LinkedList<String> ll = new LinkedList<String>();
ll.add("adb"); // 元素可重複
ll.add("adb");
ll.add(1," ");  // 內部經過遍歷刪除ll.remove(" ");
ll.add("shell");
ll.addFirst("<"); // 列表開頭插入指定的元素 對應的刪除 ll.removeFirst();
ll.addLast(">"); // 列表結尾插入指定的元素  對應的刪除 ll.removeLast();
ll.remove(3); // 刪除 index=3 的元素
for(Object l: ll){
    System.out.print(l); // <adb shell> 遍歷輸出列表元素
    // ll.listIterator(); // 正向迭代
    //ll.descendingIterator(); // 反向迭代
}
ll.push("shell"); //實質上就是將元素插入到開頭位置 addFirst()
System.out.println("\n"+ll.get(0)); // 內部經過遍歷查找 index=0 的元素 或者 ll.getFirst();
System.out.println(ll.element()); // 內部調用 getFirst()
System.out.println(ll.pop()); // 內部調用 removeFirst()
ll.clear(); // 清除列表全部元素

3-- Vector類實現了可擴展的對象數組,與ArrayList同樣有初始容量大小,超容會自動擴容爲原來的2倍,但線程是安全的。因此增刪查詢效率比ArrayList差一些。

Vector<Integer> v = new Vector<Integer>();
// Vector 繼承AbstractCollection 重寫的 toString() 方法
System.out.println(v); // 打印[] 與 ArrayList 同樣
v.add(1);
v.addElement(2);
v.insertElementAt(129, 1);
for(Object o: v)
    System.out.println(o); // 1 \n 129 \n 4 迭代 Vector 中的元素
//v.setSize(19);// 設置元素個數的大小
//System.out.println(v.capacity()); // 20
v.trimToSize();  //將容量大小變爲所包含元素個數大小
System.out.println(v.capacity()); // 3   當前列表的容量大小
v.clear();
if(v.isEmpty()) System.out.println("none ");

3、Map 接口與實現類

  • Map 接口
    Map將鍵映射到值的對象,不能包含重複的鍵。Map 中元素的順序取決於迭代器迭代時的順序,有的實現類(TreeMap)保證了元素輸入輸出時的順序,有的實現類(HashMap)則是無序的 .

  • AbstractMap 抽象類
    AbstractMap 提供了 Map 的基本實現。該抽象類中只有一個抽象方法public abstract Set<Entry<K,V>> entrySet();

  • HashMap、TreeMap、 HashTable

1-- HashMap 採用哈希表實現的鍵值對集合,底層實現鏈表數組(jdk1.8加入紅黑樹).有默認初始容量,擴容由容量和加載因子(0.75)決定。非線程安全的。

HashMap<String, String> m = new HashMap<String, String>();
m.put("1","zzz"); // key不能重複,value能夠
m.put("2","zzz");
m.put("0","");
m.put(null,"111"); // 不打印該鍵值,被最後爲null的鍵覆蓋
m.put("4",null);
m.put(null,null); // key,value容許空值
Set<String> s =m.keySet();
for(Object o: s){ // 迭代輸出 map中的 keys
    System.out.println("key:" + o);
}
Collection c = m.values();
for(Object o: c){ // 迭代輸出 map中的 values
    System.out.println("value:" + o);
}
// 迭代map
for(Map.Entry<String, String> entry: m.entrySet()){
    System.out.println(entry.getKey()+"--->"+entry.getValue());
}

2-- TreeMap 基於紅黑樹實現,按天然順序或自定義順序遍歷鍵(key),鍵不能爲null, 非線程安全

TreeMap<String, String> tm = new TreeMap<String, String>();
tm.put("1","22");
//tm.put(null,null); // 鍵不能爲null, 會拋出空指針異常
tm.put("","");
tm.put("2",null);
tm.put("0","22");
System.out.println(tm.replace("","1"));// 替換對應key的值
for(Map.Entry<String, String> entry: tm.entrySet()){
    System.out.println(entry.getKey()+"--->"+entry.getValue());
}
System.out.println("value:"+tm.get("")); // 經過key獲取 value
System.out.println("first key:" +tm.firstKey() +" ,value:"+ tm.lastKey()); // 獲取第一個key - value
System.out.println(tm.higherKey("2")); //大於給定鍵的小鍵,不存在則返回 null
System.out.println(tm.tailMap("0")); // 返回其鍵大於等於 key的鍵值
System.out.println(tm.ceilingKey("2")); //大於或等於給定鍵的鍵
System.out.println(tm.lowerKey("2")); // 小於給定鍵的最大鍵,若是沒有則返回 nul

3-- HashTable是散列表,繼承Dictionary抽象類直接實現了Map接口。鍵和值都不能爲 null,線程安全

Hashtable<String, String> ht = new Hashtable<String, String>();
 ht.put("","");
 //ht.put(null,"");  // 鍵不能爲 null
 //ht.put("1",null); // 值也不能爲 null
 ht.put("1","a");
 ht.put("2","b");
 ht.put("0","c");
 ht.put("3","d");
 Enumeration e = ht.elements();//能夠使用Enumeration 迭代器
 for(Map.Entry<String, String> entry: ht.entrySet()){
     System.out.println(entry.getKey()+"--->"+entry.getValue());
 }

4、Set 接口與實現類

  • Set 接口
    Set是一個不可重複的集合,容許包含值爲null的元素。

  • AbstractSet 抽象類
    繼承 AbstractCollection 抽象類,實現了 Set 接口。與AbstractList 不一樣,AbstractSet類中只有3 個方法 equals、hashCode、removeAll。其add,remove,clear ... 都是子類本身實現。

  • HashSet、TreeSet

1-- HashSet繼承AbstractSet抽象類,直接實現了Set接口。無序列集合,而且多線程不安全。底層經過HashMap實現,Map中key不能重複,這也就是Set不容許重複的緣由。

HashSet<String> hs = new HashSet<String>();
String str = new String("abc");
hs.add(null);
hs.add("abc");
hs.add(str); // 重複元素
hs.add("");
System.out.println(hs.size()); // 3 元素個數
// forEach 內部經過 for(T t:this){} 實現,調用的是Iterable接口(即 Collection接口的父類)中的方法,
hs.forEach(System.out::println); // 等同於 o -> System.out.println(o)
hs.removeAll(hs); // 調用父類的方法刪除全部元素
hs.addAll(Arrays.asList("a","a","b")); // 將指定集合中的全部元素添加到此集合,可用於去重

2-- TreeSet繼承AbstractSet抽象類,實現NavigableSet接口,而該接口繼承了SortedSet最後才繼承Set接口。使用元素的天然順序對元素進行排序,或者根據建立 set 時提供的 Comparator 進行排序,具體取決於使用的構造方法。

TreeSet<String> ts = new TreeSet<String>();
ts.add("aaa0"); // 迭代時,按天然排序輸出 [1, 2, 3, 4, aaa, aaa0, begin, end]
ts.add("aaa");
ts.add("begin");
ts.add("1");
ts.add("2");
ts.add("3");
ts.add("4");
ts.add("end");
for(Object o: ts)
    System.out.println(o);
System.out.println("\n"+ts.first()); // 1  返回集合中第一個元素  返回最後元素:ts.last()
System.out.println(ts.subSet("a","b")); // [aaa, aaa0] 返回範圍內部分元素
System.out.println(ts.tailSet("0")); // 返回大於或等於某元素的全部元素
System.out.println(ts.headSet("3")); // 返回小於某元素的全部元素

5、Queue 接口與實現類

  • Queue接口
    Queue 繼承自 Collection 接口 ,Deque, LinkedList, PriorityQueue, BlockingQueue 等類都實現了它。隊列一般但不必定是以FIFO(先進先出)方式排序元素。

  • Deque接口
    雙向隊列(Deque),是Queue的一個子接口,雙向隊列是指該隊列兩端的元素既能入隊(offer)也能出隊(poll).它的實現類:ArrayDeque。

  • PriorityQueue、ArrayDeque

1-- PriorityQueue繼承AbstractQueue抽象類,抽象類繼承AbstractCollection抽象類實現了Queue接口,優先隊列不容許null元素,且非線程安全的。其容器是一個object的數組。默認狀況下采用的是天然排序,取出的是隊列最小的元素。

Collection c = Arrays.asList("a","b","c");
PriorityQueue<String> pq = new PriorityQueue<String>(c);
pq.offer("0"); // 指定的元素插入到此優先級隊列
//pq.offer(null); // 不容許插入null
// pq.add(null); // 調用 offer方法插入元素
pq.offer("a"); // 容許重複的值
System.out.println(pq.remove("v"));// false 從該隊列中刪除指定元素的單個實例(若是存在)
System.out.println(pq.peek()); // 檢索但不刪除此隊列的頭,不存在則返回null
System.out.println(pq.poll()); // 檢索並刪除此隊列的頭,不存在則返回null
System.out.println(pq.size());
System.out.println(pq); // [a, a, c, b]
for(Object o : pq){
    System.out.println(o); // 遍歷隊列中的元素
}

2--ArrayDeque 繼承了AbsrtactCollection抽象類,實現了Deque接口。因此ArrayDeque擁有二者的特性。因爲是兩端隊列,因此其順序是按照元素插入數組中對應位置產生的。

Collection c = Arrays.asList("a","b","c");
 ArrayDeque<String> aq = new ArrayDeque<String>(c);
 aq.addFirst("start"); // 頭部插入指定元素 等同於offerFirst
 aq.addLast("end"); // 尾部插入指定元素 等同於offerLast
 //aq.add(null); // 不容許插入null
 aq.add("0"); // 末尾插入指定的元素, 調用addLast
 System.out.println(aq);
 System.out.println(aq.getFirst()); // start 檢索但不刪除,這個deque的第一個元素
 System.out.println(aq.getLast()); // 0 檢索但不刪除,這個deque的最後一個元素
 aq.offer("in"); // 調用 offerLast 再調用 addLast.實質與add同樣。
 System.out.println(aq.pop()); // 刪除第一個元素 調用 removeFirst 再調用 pollFirst
 System.out.println(aq.poll()); // 刪除第一個元素 調用 pollFirst
 aq.push("me"); // 將元素推到第一個位置 調用 addFirst
 System.out.println(aq);

6、Collections 和 Arrays 工具類

Collections該工具類提供了大量方法對集合進行排序、查詢和修改等操做,還提供了將集合對象置爲不可變、對集合對象實現同步控制等方法。
Arrays 工具類提供了將數組轉換爲集合的方法 Arrays.asList().

List<String> l = Arrays.asList("a","b","c","d","e","f");
// 對列表中的元素進行翻轉
Collections.reverse(l);
System.out.println(l); // [f, e, d, c, b, a]
//l.add("1"); 會拋出異常java.lang.UnsupportedOperationException,Arrays.asList()返回的是其內部類的 new ArrayList()對象
// 而其內部類沒有重寫 AbstractList中的add方法,因此調用的是父類的add,而父類的add方法直接拋出異常
List<String> nl = new ArrayList<>(l);
nl.add("0");
// 對列表默認順序(天然順序)進行排序
Collections.sort(nl);
System.out.println(nl); // [0, a, b, c, d, e, f]
nl.add("aa");
// 根據其元素的 天然順序返回給定集合的最大\小元素
System.out.println( Collections.max(l)); // f
System.out.println( Collections.min(l)); // a
System.out.println(nl); // [0, a, b, c, d, e, f, aa]
// 使用指定的隨機源隨機排列指定的列表
Collections.shuffle(nl, new Random()); // 不帶種子的隨機數,每次都不同。反之,每次都同樣
System.out.println(nl); // [b, aa, f, d, 0, c, a, e]
// 若是兩個指定的集合沒有共同的元素,則返回 true
System.out.println(Collections.disjoint(l, nl));

注:
http://www.trinea.cn/category/java/
http://www.cnblogs.com/midiyu/p/8145503.html
http://www.benchresources.net/java/collection-framework/
https://blog.csdn.net/u011240877/article/category/6447444
https://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html

相關文章
相關標籤/搜索