java集合包總結(新增、刪除等操作實現原理)
1.集合包
常用的是Collection與Map兩個介面的實現類。
Collection常用的兩種介面:List和Set。
List實現類:ArrayList、LinkedList、Vector、Stack。
Set實現類:HashSet、TreeSet。
Collection主要包括建立、增加、刪除、獲取單個物件、遍歷物件、判斷物件是否存在與Collection中、物件的排序。
1.1ArrayList
建立:ArrayList採用陣列的方式來存放物件,建立一個大小為10的Object陣列。
插入物件:
問題:傳入物件陣列滿了,怎麼辦?
當呼叫add方法時,首先基於ArrayList中已有的元素加
Arrays.copyOf方法實現:建立一個新陣列物件,該陣列物件的型別和之前的ArrayList中的元素的型別一致。(JDK優化,如果是Object型別,直接通過new Object[newLength]
Collection中增加物件,ArrayList提供一個add(int,E)這樣的方法,允許元素直接插入指定的int位置上(這個方法要確保插入的位置存在,確保容量夠用)。但與add()方法不同,他要將當前陣列的物件進行復制,將其後的資料都往後挪動一位,然後才能將指定的index位置的賦值為傳入的物件。
除了add(),ArrayList還提供了set(int ,E)方法替換原來指定位置的物件。
刪除物件:
remove(E):遍歷陣列,將找到的相同物件刪除(如果有重複的只刪除一個),將index後面的物件往前複製一位。remove(int)刪除指定位置的物件,它比remove(E):多一個數組範圍的檢測,但少了物件位置的查詢,效能更好。
獲取單個物件:
獲得陣列元素的位置,先做範圍檢測,然後可直接返回陣列中位於此位置的物件。
遍歷物件:
Iterator由ArrayList的父類AbstractList實現,當每次呼叫iterator方法時,都會建立一個新的AbstractList內部Itr的例項。當呼叫此例項的hasNext方法時,比較指定位置的陣列是否和陣列中已有的元素大小相等。如果相等放回false,否則返回true。
判斷物件是否存在:
Contains(E):遍歷ArrayList已有元素。
indexOf和lastIndexOf是ArrayList用於獲取物件所在位置的方法,IndexOf從前往後尋找,lastIndexOf從後向前。
注意
1.ArrayList基於陣列,無容量限制。
2.ArrayList插入元素可能需要擴容,刪除元素並不會減少陣列的容量(如果希望相應的縮小陣列容量,可以呼叫ArrayList的trimToSize()),在查詢元素時需要遍歷陣列,對於非null元素採用equals的方式尋找。
3.ArrayList非執行緒安全。
1.2LinkedList
實現方式:基於雙向連結串列機制,就是集合中的每個元素都知道其前一個元素及其後一個元素的位置。在LinkedList中,內部類Entry類來代表集合中的元素,元素值賦給element屬性,Entry的next屬性指向後一個元素,Entry中的previous屬性指向元素的前一個原理,這樣可以快速實現集合中元素的移動。
add(E):
向LinkedList中增加元素,就要建立Entry物件,完成新增操作連結串列的處理,始終保持雙向連結串列的閉環。LinkedList add方法不需要考慮擴容及複製陣列的問題。
remove(E)
刪除LinkedList的一個元素也要遍歷LinkedList中的元素,遍歷和尋找匹配的元素的方法和ArrayList基本相同,但是刪除元素的方法比ArrayList簡單。
get(int)
由於LinkedList的元素並沒有儲存在一個數組中,因此get操作複雜。執行get操作的時候,首先要判斷傳入的index值是否合理。如果不符合,丟擲IndexOutOfBoundsException。(如果值小於一半,則從頭一直找到index位置所對應的next元素,如果大於,則從尾部往前,一直找到index位置所對應的previous元素)。
Iterator()
當呼叫Iterator()返回的hasnext方法時,判斷當前cursor的位置是否等同於LinkedList的size變數,等於返回true,不等於返回false。如在遍歷中增加或刪除,則會丟擲ConcurrentModificationException異常。也可以通過hasPrevious和prevoius來完成遍歷。
contains(E)
LinkedList也是採用的遍歷所有元素的方法。
注意:
1.LinkedList基於雙向連結串列機制實現
2.LinkedList插入與刪除原理
3.LinkedList是非執行緒安全的
1.3Vector
Vector() 預設建立一個大小為10的Object陣列,設定一個引數capacityIncrement設定為0。
add(E):Vector中add方法加了synchorized關鍵字,因此方法執行緒安全,除此與ArrayList基本相同。除擴充陣列:如果capacityIncrement大於0,則將Object陣列大小擴大為size加上capacityIncrement的值。如果capacityIncrement <=0 ,在將Object陣列擴大為現在size的兩倍。這種容量的控制策略比ArrayList更為可控。
remove(E)
除了呼叫removeElement方法上有synchorized關鍵字外,其他和ArrayList完全相同。
get(int)
此方法同樣有synchorized
Iterator
和ArrayList完全一樣
contains(E)
Indexof放有synchorized方法
注意
Vector是基於synchorized實現的執行緒安全ArrayList。
1.4Stack
實現方式
Stack繼承於Vector,在其基礎上實現LIFO的彈出和壓入,提供了push、pop、peek三個主要的方法。
push
通過呼叫Vector中的addElement來完成。
pop
呼叫peek獲取元素,並同時刪除陣列的最後一個元素。
peek
Peek根據當前Object陣列的大小,並取得最後一個元素
1.5HashSet
HashSet是Set介面的實現,與List明顯的區別在於Set不允許元素重複,而List允許。Set為了做到不允許元素重複,採用的是基於HashMap來實現。
HashSet
要建立一個HashMap物件。
add()
呼叫HashMap的put()方法來完成此操作,將需要增加的元素作為map中key,value則傳入一個之前已建立的Object物件。
remove(E)
使用HashMap的remove(E)方法來完成此操作。
Iterator
呼叫HashMap的keySet的iterator方法來完成此操作。HashSet不支援通過get(int)獲取指定位置的元素,只能通過iterator方法獲取。
注意要點:
對於HashSet而言,需要注意以下幾點:
1.HashSet基於HashMap實現,無容量限制
2.HashSet是非執行緒安全的。
1.6TreeSet
TreeSet和HashSet主要不同在於TreeSet對於排序的支援,TreeSet基於TreeMap實現
Iterator
呼叫TreeSet的navigableKeySet的iterator方法完成此操作。
TreeSet和HashSet一樣都是基於Map完成,也不支援get(int)操作獲取指定位置的元素。TreeSet基於TreeMap,TreeSet還提供了一些排序方面的支援。TreeSet非執行緒安全。
1.7HashMap
HashMap是Map最常用的實現
HashMap(): 將loadFactor設定為0.75,threshold設定為12,並建立一個大小為16的Entry物件陣列。
put(key,value):key為null時,HashMap的做法為獲取Entry陣列中的第一個Entry物件,並基於Entry物件的next屬性遍歷。若找到key為null的Entry物件,則將value賦值為新的value。
若沒有key為null的Entry,則增加一個Entry物件。如果此時Entry陣列已用的大小 >=threshold,則將Entry陣列擴大為當前大小的兩倍。擴大時對當前Entry物件陣列中的元素重新hash,並填充陣列,最後重新設定threshhold值。
解決hash衝突,來看看HashMap的解決方法。如果找到hash值相等的Entry物件,替換此Entry物件的值,並返回舊的值。如未找到,向對應的陣列位置增加新的Entry物件,增加時採取的方法和key為null的情況基本相同,只是它替換指定位置的Entry物件。所以hashmap解決衝突的是連結串列的方式,而不是開放定址法。
get(key)
key為null的情況,直接獲取陣列中的第一個Entry物件,並且基於next屬性進行遍歷,尋找key為null的Entry物件,如找到則返回null,對於key為非null的情況,則對key進行hash和按位與操作,找到對應的儲存位置,然後獲取次位置對應的Entry物件,基於next屬性遍歷,尋找hash值相等,且key相等的Entry物件,返回其value,如果未找到,則返回null。
remove()
與get相似,只是在找到匹配的key後,將陣列上的元素的值置為其next元素的值。
containsKey()
通過getEntry方法來完成,getEntry與get過程基本相同,知識找到匹配餓的key後,直接返回Entry物件,containsKey返回false或者true。
keySet()
呼叫keySet()返回一個HashMap中的keySet例項。HashMap無法保證順序輸出,若要按順序,使用TreeMap。HashMap非執行緒安全的。
注意要點
HashMap
1HashMap採用陣列方式儲存key、value構成的Entry物件,無容量限制。
2HashMap基於key hash尋找Entry物件存放到陣列的位置,對於hash衝突採用連結串列的方式解決。
3HashMap在插入元素時可能會要擴大陣列的容量,在擴大容量時,要重新計算hash,並複製到新的陣列。
4HashMap執行緒非安全
1.8TreeMap
實現方式:支援排序的Map實現,但是實現方式與HashMap並不相同。
TreeMap()
將comparator屬性賦值為null,控制儲存順序需要使用Comparator引數的構造器。
put(key,value)
基於紅黑樹的方式遍歷,基於comparator來比較應放在左邊還是右邊,如果key相等,則替換其value,並返回結束put操作。如果沒找到相等的key,則一直尋找左邊或右邊節點為null的元素,如comparator實現為null,則判斷key是否為null,則丟擲NullPointerException。
TreeMap是典型的紅黑樹實現,因此它要求一定要有key比較的方法,要麼傳入Comparator實現,要麼key實現Comparatable介面
get()
紅黑樹查詢
remove()
首先要getEntry,然後將此Entry從紅黑樹上刪除,並重新調整樹上的相關的節點。
containsKey()
和get方法一樣,都是通過getEntry方法來完成,因此過程和get方法一樣,只是containsKey直接判斷返回的Entry是否為null,為null返回false,否則,返回true。
keySet()
Iterator的遍歷從跟開始,基於紅黑樹順序完成。
注意要點
1.TreeMap基於紅黑樹,無容量限制
2.TreeMap非執行緒安全。