Java中的集合包括三大類,它們是Set、List和Map,
它們都處於java.util包中,Set、List和Map都是接口,它們有各自的實現類。
List、Set都繼承自Collection接口,Collection (全部集合類的接口)
容器內每一個爲之所存儲的元素個數不一樣。Collection類型者,每一個位置只有一個元素。Map類型者,持有 key-value pair,像個小型數據庫。html
List,Set都是繼承自Collection接口,Map則不是java
(a) Collection
--List:將以特定次序存儲元素。因此取出來的順序可能和放入順序不一樣。
--ArrayList / LinkedList / Vector
--Set : 不能含有重複的元素
--HashSet / TreeSet
(b) Map
--HashMap
--HashTable
--TreeMap web
List,Set,Map將持有對象一概視爲Object型別。數據庫
Collection、List、Set、Map都是接口,不能實例化。 繼承自它們的 ArrayList, Vector, HashTable, HashMap是具象class,這些纔可被實例化。
vector容器確切知道它所持有的對象隸屬什麼型別。vector不進行邊界檢查。編程
8. map的 key 集合和 set集合都不容許有重複的元素存在,list能夠有重複的元素存在 數組
(2)List中的對象按照索引位置排序,能夠有重複對象,容許按照對象在集合中的索引位置檢索對象,如經過list.get(i)方式來得到List集合中的元素。
(3)Set中的對象不按特定方式排序,而且沒有重複對象。但它的有些實現類能對集合中的對象按特定方式排序,例如TreeSet類,它能夠按照默認排序,也能夠經過實現 java.util.Comparator<Type>接口來自定義排序方式。
(4) Map中的每個元素包含一個鍵對象和值對象,它們成對出現。鍵對象不能重複,值對象能夠重複。安全
關係如圖:
或者:數據結構
Collections (操做集合的工具類)
對於集合類的操做不得不提到工具類Collections,它提供了許多方便的方法,如求兩個集合的差集、並集、拷貝、排序等等。
因爲大部分的集合接口實現類都是不一樣步的,可使用Collections.synchronized*方法建立同步的集合類對象。
如建立一個同步的List:
List synList = Collections.synchronizedList(new ArrayList());
其實現原理就是從新封裝new出來的對象,操做對象時用關鍵字synchronized同步。看源碼很容易理解。
Collections部分源碼: 多線程
static class SynchronizedCollection<e> implements Collection<e>, Serializable { final Collection<e> c; // Backing Collection final Object mutex; // Object on which to synchronize SynchronizedCollection(Collection<e> c) { if (c==null) throw new NullPointerException(); this.c = c; mutex = this; } //... public boolean add(E e) { //操做集合時簡單調用本來的ArrayList對象,只是作了同步 synchronized (mutex) {return c.add(e);} } //...
ArrayList、Vector是線性表,使用Object數組做爲容器去存儲數據的,添加了不少方法維護這個數組,使其容量能夠動態增加,極大地提高了開發效率。它們明顯的區別是ArrayList是非同步的,Vector是同步的。不用考慮多線程時應使用ArrayList來提高效率。app
LinkedList是鏈表,略懂數據結構就知道其實現原理了。鏈表隨機位置插入、刪除數據時比線性錶快,遍歷比線性錶慢。
由此可根據實際狀況來選擇使用ArrayList(非同步、非頻繁刪除時選擇)、Vector(需同步時選擇)、LinkedList(頻繁在任意位置插入、刪除時選擇)。
HashMap結構的實現原理是將put進來的key-value封裝成一個Entry對象存儲到一個Entry數組中,位置(數組下標)由key的哈希值與數組長度計算而來。若是數組當前下標已有值,則將數組當前下標的值指向新添加的Entry對象。
public class HashMap<k,v> extends AbstractMap<k,v> implements Map<k,v>, Cloneable, Serializable { transient Entry<k,v>[] table; public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key); int i = indexFor(hash, table.length); //遍歷當前下標的Entry對象鏈,若是key已存在則替換 for (Entry<k,v> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } addEntry(hash, key, value, i); return null; } } static class Entry<k,v> implements Map.Entry<k,v> { final K key; V value; Entry<k,v> next; int hash; }
TreeMap是由Entry對象爲節點組成的一顆紅黑樹,put到TreeMap的數據默認按key的天然順序排序,new TreeMap時傳入Comparator自定義排序。紅黑樹網上不少資料,我講不清,這裏就不介紹了。
之因此先講Map是由於Set結構其實就是維護一個Map來存儲數據的,利用Map結構key值惟一性。
HashSet部分源碼:
public class HashSet<e> extends AbstractSet<e> implements Set<e>, Cloneable, java.io.Serializable { //無心義對象來做爲Map的value private static final Object PRESENT = new Object(); public boolean add(E e) { return map.put(e, PRESENT)==null; } }
線程安全類
在集合框架中,有些類是線程安全的,這些都是jdk1.1中的出現的。在jdk1.2以後,就出現許許多多非線程安全的類。 下面是這些線程安全的同步的類:
vector:就比arraylist多了個同步化機制(線程安全),由於效率較低,如今已經不太建議使用。在web應用中,特別是前臺頁面,每每效率(頁面響應速度)是優先考慮的。
statck:堆棧類,先進後出
hashtable:就比hashmap多了個線程安全
enumeration:枚舉,至關於迭代器
除了這些以外,其餘的都是非線程安全的類和接口。
線程安全的類其方法是同步的,每次只能一個訪問。是重量級對象,效率較低。
具體的區別請參考:HashMap、HashTable、ConcurrentHashMap、HashSet區別 線程安全類
StringBuffer是線程安全,而StringBuilder是線程不安全的。對於安全與不安全沒有深刻的理解狀況下,易形成這樣的錯覺,若是對於StringBuffer的操做均是線程安全的,然而,Java給你的保證的線程安全,是說它的方法是執行是排它的,而不是對這個對象自己的屢次調用狀況下,仍是安全的。看看下邊的例子,在StringBufferTest中有一個數據成員contents它是用來擴展的,它的每一次append是線程安全的,但衆屢次append的組合並非線程安全的,這個輸出結果不是太可控的,但若是對於log和getContest方法加關鍵字synchronized,那麼結果就會變得很是條理,若是換成StringBuider甚至是append到一半,它也會讓位於其它在此基礎上操做的線程: