簡介
Java中集合類有很多,只介紹常用的集合類:
線程安全和非線程安全的集合對象
一、概念:
- 線程安全:就是當多線程訪問時,采用了加鎖的機制;即當一個線程訪問該類的某個數據時,會對這個數據進行保護,其他線程不能對其訪問,直到該線程讀取完之后,其他線程才可以使用。防止出現數據不一致或者數據被污染的情況。
- 線程不安全:就是不提供數據訪問時的數據保護,多個線程能夠同時操作某個數據,從而出現數據不一致或者數據污染的情況。
- 對於線程不安全的問題,一般會使用synchronized關鍵字加鎖同步控制。
- 線程安全工作原理: jvm中有一個main memory對象,每一個線程也有自己的working memory,一個線程對於一個變量variable進行操作的時候, 都需要在自己的working memory里創建一個copy,操作完之后再寫入main memory。 當多個線程操作同一個變量variable,就可能出現不可預知的結果。
而用synchronized的關鍵是建立一個監控monitor,這個monitor可以是要修改的變量,也可以是其他自己認為合適的對象(方法),然后通過給這個monitor加鎖來實現線程安全,每個線程在獲得這個鎖之后,要執行完加載load到working memory 到 use && 指派assign 到 存儲store 再到 main memory的過程。才會釋放它得到的鎖。這樣就實現了所謂的線程安全。
二、線程安全(Thread-safe)的集合對象:
- Vector 線程安全:
- HashTable 線程安全:
- StringBuffer 線程安全:
三、非線程安全的集合對象:
- ArrayList :
- LinkedList:
- HashMap:
- HashSet:
- TreeMap:
- TreeSet:
- StringBulider:
四、相關集合對象比較:
Vector、ArrayList、LinkedList:
1、Vector:
Vector與ArrayList一樣,也是通過數組實現的,不同的是它支持線程的同步,即某一時刻只有一個線程能夠寫Vector,避免多線程同時寫而引起的不一致性,但實現同步需要很高的花費,因此,訪問它比訪問ArrayList慢。
2、ArrayList:
a. 當操作是在一列數據的后面添加數據而不是在前面或者中間,並需要隨機地訪問其中的元素時,使用ArrayList性能比較好。
b. ArrayList是最常用的List實現類,內部是通過數組實現的,它允許對元素進行快速隨機訪問。數組的缺點是每個元素之間不能有間隔,當數組大小不滿足時需要增加存儲能力,就要講已經有數組的數據復制到新的存儲空間中。當從ArrayList的中間位置插入或者刪除元素時,需要對數組進行復制、移動、代價比較高。因此,它適合隨機查找和遍歷,不適合插入和刪除。
3、LinkedList:
a. 當對一列數據的前面或者中間執行添加或者刪除操作時,並且按照順序訪問其中的元素時,要使用LinkedList。
b. LinkedList是用鏈表結構存儲數據的,很適合數據的動態插入和刪除,隨機訪問和遍歷速度比較慢。另外,他還提供了List接口中沒有定義的方法,專門用於操作表頭和表尾元素,可以當作堆棧、隊列和雙向隊列使用。
Vector和ArrayList在使用上非常相似,都可以用來表示一組數量可變的對象應用的集合,並且可以隨機的訪問其中的元素。
ArryList和LinkedList的區別:
Vector與ArrayList比較:
1. 性能上
ArrayList底層數據結構是數組,適合隨機查找和遍歷,不適合插入和刪除,線程不安全,效率高。。LinkedList底層數據結構是鏈表, 適合數據的動態插入和刪除,隨機訪問和遍歷速度比較慢,線程不安全,效率高。。
HashTable、HashMap、HashSet:
HashTable和HashMap采用的存儲機制是一樣的,不同的是:
1、HashMap:
a. 采用數組方式存儲key-value構成的Entry對象,無容量限制;
b. 基於key hash查找Entry對象存放到數組的位置,對於hash沖突采用鏈表的方式去解決;
c. 在插入元素時,可能會擴大數組的容量,在擴大容量時須要重新計算hash,並復制對象到新的數組中;
d. 是非線程安全的;
e. 遍歷使用的是Iterator迭代器;
2、HashTable:
a. 是線程安全的;
b. 無論是key還是value都不允許有null值的存在;在HashTable中調用Put方法時,如果key為null,直接拋出NullPointerException異常;
c. 遍歷使用的是Enumeration列舉;
3、HashSet:
a. 基於HashMap實現,無容量限制;
b. 是非線程安全的;
c. 不保證數據的有序;
TreeSet、TreeMap:
TreeSet和TreeMap都是完全基於Map來實現的,並且都不支持get(index)來獲取指定位置的元素,需要遍歷來獲取。另外,TreeSet還提供了一些排序方面的支持,例如傳入Comparator實現、descendingSet以及descendingIterator等。
1、TreeSet:
a. 基於TreeMap實現的,支持排序;
b. 是非線程安全的;
2、TreeMap:
a. 典型的基於紅黑樹的Map實現,因此它要求一定要有key比較的方法,要么傳入Comparator比較器實現,要么key對象實現Comparator接口;
b. 是非線程安全的;
Collection有兩個子接口:List和Set,二者主要區別在於:list數據有序存放、可重復;set中數據無序存放,不可重復。
Vector
Vector類實現了一個動態數組,主要用在事先不知道數組的大小,以及需要頻繁地進行查找,插入,刪除工作,或者只是需要一個可以改變大小的數組的情況。
創建:
Vector類支持4種構造方法。
第一種構造方法創建一個默認的向量,默認大小為10:
Vector()
第二種構造方法創建指定大小的向量。
Vector(int size)
第三種構造方法創建指定大小的向量,並且增量用incr指定. 增量表示向量每次增加的元素數目(當該vector對象添加的元素接近原先分配的內存極限時,會以incr大小自動擴大該對象擁有的內存容量,以容納更多的數據)
Vector(int size,int incr)
第四中構造方法創建一個包含集合c元素的向量:利用父類對象創建子類對象
Vector(Collection c)
常用的vector操作方法:增、刪、查、改。
增:
vec.add(E element)
將指定元素追加到此向量的末尾。
vec.add(int index, E element)
在此向量的指定位置插入指定的元素。
vec.addAll(Collection c)
將指定 Collection 中的所有元素按順序追加到此向量的末尾。
vec.addAll(int index, Collection c)
在指定位置將指定 Collection 中的所有元素插入到此向量中。
刪:
vec.remove(int index)
移除此向量中指定位置的元素。
vec.remove(value v)
移除向量中元素值為v的元素。
vec.removeAll(Collection c)
從此向量中移除包含在集合c 中的所有元素。
vec.removeAllElements()
從此向量中移除全部組件,並將其大小設置為零。
vec.removeRange(int fromIndex, int toIndex)
移除位於 fromIndex(包括)與 toIndex(不包括)之間的所有元素。
vec.clear() 移除所有元素。
查:
vec.get(int index)
返回向量中指定位置的元素。
vex.indexOf(value v)
返回v值在vec中的下標。
vec.isEmpty()
檢查該向量是否為空。
vec.lastElement()
返回此向量的最后一個元素。
int capacity()
返回此向量的當前容量。
int size()
返回此向量中的組件數。
String toString()
返回此向量的字符串表示形式,其中包含每個元素的 String 表示形式。
改:
vec.set(int index, E element)
用指定的元素替換此向量中指定位置處的元素。
vex.setElementAt(E obj, int index)
將此向量指定 index 處的組件設置為指定的對象。
vec.setSize(int newSize)
設置此向量的大小。
ArrayList
ArrayList就是動態的數組,可以動態的增加和減少元素,靈活的設置數組的大小。基本與Vector一樣。
創建:
ArrayList提供了三個構造器:
public ArrayList();
默認的構造器,將會以默認(16)的大小來初始化內部的數組
public ArrayList(Collection c);
用一個集合對象來構造,並將該集合的元素添加到ArrayList
public ArrayList(int n);
用指定n的大小來初始化內部的數組.
增:
方法摘要 | |
---|---|
boolean |
add(E e) 將指定的元素添加到此列表的尾部。 |
void |
add(int index, E element) 將指定的元素插入此列表中的指定位置。 |
boolean |
addAll(Collection<? extends E> c) 按照指定 collection 的迭代器所返回的元素順序,將該 collection 中的所有元素添加到此列表的尾部。 |
boolean |
addAll(int index, Collection<? extends E> c) 從指定的位置開始,將指定 collection 中的所有元素插入到此列表中。 |
刪:
E |
remove(int index) 移除此列表中指定位置上的元素。 |
boolean |
remove(Object o) 移除此列表中首次出現的指定元素(如果存在)。 |
protected void |
removeRange(int fromIndex, int toIndex) 移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之間的所有元素。 |
void |
clear() 移除此列表中的所有元素。 |
查:
E |
get(int index) 返回此列表中指定位置上的元素。 |
int |
indexOf(Object o) 返回此列表中首次出現的指定元素的索引,或如果此列表不包含元素,則返回 -1。 |
boolean |
isEmpty() 如果此列表中沒有元素,則返回 true |
int |
size() 返回此列表中的元素數。 |
boolean |
contains(Object o) 如果此列表中包含指定的元素,則返回 true。 |
ArrayList支持3種遍歷方式
第一種,通過迭代器遍歷。
Integer value = null; Iterator iter = list.iterator(); while (iter.hasNext()) { value = (Integer)iter.next(); }
第二種,隨機訪問,通過索引值去遍歷。
Integer value = null;for (int i=0; i<list.size(); i++) { value = (Integer)list.get(i); }
第三種,for-each遍歷。
Integer value = null; for (Integer integ:list) { value = integ; }
改:
E |
set(int index, E element) 用指定的元素替代此列表中指定位置上的元素。 |
Object[] |
toArray() |
HashMap
這里我們先講hashmap,具體原因等講到hashset的時候就知道了。
構造方法摘要 | |
---|---|
HashMap() 構造一個具有默認初始容量 (16) 和默認加載因子 (0.75) 的空 HashMap。 |
|
HashMap(int initialCapacity) 構造一個帶指定初始容量和默認加載因子 (0.75) 的空 HashMap。 |
|
HashMap(int initialCapacity, float loadFactor) 構造一個帶指定初始容量和加載因子的空 HashMap。 |
|
HashMap(Map<? extends K,? extends V> m) 構造一個映射關系與指定 Map 相同的 HashMap。 |
void |
|
查:
boolean |
isEmpty() 如果此映射不包含鍵-值映射關系,則返回 true。 |
Set<K> |
keySet() 返回此映射中所包含的鍵的 set 。//獲取hashmap中的key集合。 |
Collection<V> |
values() 返回此映射所包含的值的 collection 視圖。 |
int |
size() 返回此映射中的鍵-值映射關系數。 |
boolean |
containsKey(Object key) 如果此映射包含對於指定的鍵的映射關系,則返回 true。 |
boolean |
containsValue(Object value) 如果此映射將一個或多個鍵映射到指定值,則返回 true。 |
HashSet
刪除一個元素:hashSet.remove(Object);
刪除所有元素:hashSet.clear();
查:
用迭代器遍歷:
Iterator it = hashSet.iterator();
while(it.hasNext()){
Object obj = it.next();
然后針對obj進行一系列的操作,比如:輸出值、如果obj是類對象則調用屬性、方法。
}
boolean |
contains(Object o) 如果此 set 包含指定元素,則返回 true。 |
boolean |
isEmpty() 如果此 set 不包含任何元素,則返回 true。 |
int |
size() 返回此 set 中的元素的數量(set 的容量)。 |
當從HashSet中訪問元素時,HashSet先計算該元素的hashCode值(也就是調用該對象的hashCode())方法的返回值),然后直接到該hashCode對應的位置去取出該元素。 為了保證HashSet能正常工作,要求當兩個對象用equals比較相等時,hashCode也要相等,否則就會有可能加入兩個相同的項。
HashSet的特點:
(1)HashSet不是同步的,多個線程訪問是需要通過代碼保證同步
(2)集合元素值可以為null。