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

【簡圖】
- Set 不可重復集合
- List 有序,重復集合
- Map 具有映射關系 key-value集合
- Queue、Deue 隊列集合
注:順序分為 自然排序[a-z], 添加元素的排序
一、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);
}
二、List 接口與實現類
-
List
List是一個有序可重復的集合,常用的List實現類 ArrayList, LinkedList和Vector。List接口實現類在實現插入元素時,都會根據索引進行排列,會改變其他元素的位置。 -
AbstractList
繼承 AbstractCollection 抽象類,實現了 List 接口 ,是 ArrayList 和 AbstractSequentiaList 的父類。AbstractList 內部已經提供了 Iterator, ListIterator 迭代器的實現類Itr ,ListItr。 -
ArrayList、LinkedList、Vector
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一樣也是線程不安全。雙向鏈表,不存在元素限制,沒有擴容機制。其查詢效率差,增刪效率高。
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 ");
三、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());
}
四、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")); // 返回小于某元素的所有元素
五、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);
六、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.rzrgm.cn/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

浙公網安備 33010602011771號