1. 程式人生 > >java集合包總結(新增、刪除等操作實現原理)

java集合包總結(新增、刪除等操作實現原理)

1.集合包

常用的是CollectionMap兩個介面的實現類。

Collection常用的兩種介面:ListSet

List實現類:ArrayListLinkedListVectorStack

Set實現類:HashSetTreeSet

Collection主要包括建立、增加、刪除、獲取單個物件、遍歷物件、判斷物件是否存在與Collection中、物件的排序。

1.1ArrayList

建立ArrayList採用陣列的方式來存放物件,建立一個大小為10Object陣列。

插入物件

問題:傳入物件陣列滿了,怎麼辦?

當呼叫add方法時,首先基於ArrayList中已有的元素加

1,產生minCapacity變數,然後比較此值和Object陣列的大小,如果此值大於Object陣列值,將Object陣列值賦給新的陣列物件,產生一個新的陣列容量值。此值的計算方法是當前陣列值x 1.5+1,如果容量值仍然小於minCapacity,那麼就以minCapacity作為新的容量值。得出容量值後,呼叫Arrays.copyOf來生成新的陣列物件。(如果想調整容量的增長策略,可繼承ArrayList

Arrays.copyOf方法實現:建立一個新陣列物件,該陣列物件的型別和之前的ArrayList中的元素的型別一致。(JDK優化,如果是Object型別,直接通過new Object[newLength]

建立,如果不是,則通過Array.newInstance呼叫native方法建立相同型別的陣列;建立完陣列物件之後,呼叫System.arraycopy通過native方法將之前陣列中的物件複製到新的陣列中)

Collection中增加物件,ArrayList提供一個add(intE)這樣的方法,允許元素直接插入指定的int位置上(這個方法要確保插入的位置存在,確保容量夠用)。但與add()方法不同,他要將當前陣列的物件進行復制,將其後的資料都往後挪動一位,然後才能將指定的index位置的賦值為傳入的物件。

除了add()ArrayList還提供了set(int ,E)方法替換原來指定位置的物件。

刪除物件:

   remove(E):遍歷陣列,將找到的相同物件刪除(如果有重複的只刪除一個),將index後面的物件往前複製一位。remove(int)刪除指定位置的物件,它比remove(E):多一個數組範圍的檢測,但少了物件位置的查詢,效能更好。

獲取單個物件:

獲得陣列元素的位置,先做範圍檢測,然後可直接返回陣列中位於此位置的物件。

遍歷物件:

IteratorArrayList的父類AbstractList實現,當每次呼叫iterator方法時,都會建立一個新的AbstractList內部Itr的例項。當呼叫此例項的hasNext方法時,比較指定位置的陣列是否和陣列中已有的元素大小相等。如果相等放回false,否則返回true

判斷物件是否存在:

Contains(E):遍歷ArrayList已有元素。

indexOflastIndexOfArrayList用於獲取物件所在位置的方法,IndexOf從前往後尋找,lastIndexOf從後向前。

注意

1.ArrayList基於陣列,無容量限制。

2.ArrayList插入元素可能需要擴容,刪除元素並不會減少陣列的容量(如果希望相應的縮小陣列容量,可以呼叫ArrayListtrimToSize()),在查詢元素時需要遍歷陣列,對於非null元素採用equals的方式尋找。

3.ArrayList非執行緒安全。

1.2LinkedList

實現方式:基於雙向連結串列機制,就是集合中的每個元素都知道其前一個元素及其後一個元素的位置。在LinkedList中,內部類Entry類來代表集合中的元素,元素值賦給element屬性,Entrynext屬性指向後一個元素,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的位置是否等同於LinkedListsize變數,等於返回true,不等於返回false。如在遍歷中增加或刪除,則會丟擲ConcurrentModificationException異常。也可以通過hasPreviousprevoius來完成遍歷。

contains(E)

LinkedList也是採用的遍歷所有元素的方法。

注意:

1.LinkedList基於雙向連結串列機制實現

2.LinkedList插入與刪除原理

3.LinkedList是非執行緒安全的

1.3Vector

Vector() 預設建立一個大小為10Object陣列,設定一個引數capacityIncrement設定為0

add(E):Vectoradd方法加了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的彈出和壓入,提供了pushpoppeek三個主要的方法。

push

通過呼叫Vector中的addElement來完成。

pop

呼叫peek獲取元素,並同時刪除陣列的最後一個元素。

peek

Peek根據當前Object陣列的大小,並取得最後一個元素

1.5HashSet

HashSetSet介面的實現,與List明顯的區別在於Set不允許元素重複,而List允許。Set為了做到不允許元素重複,採用的是基於HashMap來實現。

HashSet

要建立一個HashMap物件。

add()

呼叫HashMapput()方法來完成此操作,將需要增加的元素作為mapkeyvalue則傳入一個之前已建立的Object物件。

remove(E)

使用HashMapremove(E)方法來完成此操作。

Iterator

呼叫HashMapkeySetiterator方法來完成此操作。HashSet不支援通過get(int)獲取指定位置的元素,只能通過iterator方法獲取。

注意要點:

對於HashSet而言,需要注意以下幾點:

1.HashSet基於HashMap實現,無容量限制

2.HashSet是非執行緒安全的。

1.6TreeSet

TreeSetHashSet主要不同在於TreeSet對於排序的支援,TreeSet基於TreeMap實現

Iterator

呼叫TreeSetnavigableKeySetiterator方法完成此操作。

TreeSetHashSet一樣都是基於Map完成,也不支援get(int)操作獲取指定位置的元素。TreeSet基於TreeMapTreeSet還提供了一些排序方面的支援。TreeSet非執行緒安全。

1.7HashMap

HashMapMap最常用的實現

HashMap(): loadFactor設定為0.75threshold設定為12,並建立一個大小為16Entry物件陣列。

put(key,value):keynull時,HashMap的做法為獲取Entry陣列中的第一個Entry物件,並基於Entry物件的next屬性遍歷。若找到keynullEntry物件,則將value賦值為新的value

若沒有keynullEntry,則增加一個Entry物件。如果此時Entry陣列已用的大小 >=threshold,則將Entry陣列擴大為當前大小的兩倍。擴大時對當前Entry物件陣列中的元素重新hash,並填充陣列,最後重新設定threshhold值。

解決hash衝突,來看看HashMap的解決方法。如果找到hash值相等的Entry物件,替換此Entry物件的值,並返回舊的值。如未找到,向對應的陣列位置增加新的Entry物件,增加時採取的方法和keynull的情況基本相同,只是它替換指定位置的Entry物件。所以hashmap解決衝突的是連結串列的方式,而不是開放定址法。

get(key)

keynull的情況,直接獲取陣列中的第一個Entry物件,並且基於next屬性進行遍歷,尋找keynullEntry物件,如找到則返回null,對於key為非null的情況,則對key進行hash和按位與操作,找到對應的儲存位置,然後獲取次位置對應的Entry物件,基於next屬性遍歷,尋找hash值相等,且key相等的Entry物件,返回其value,如果未找到,則返回null

remove()

get相似,只是在找到匹配的key後,將陣列上的元素的值置為其next元素的值。

containsKey()

通過getEntry方法來完成,getEntryget過程基本相同,知識找到匹配餓的key後,直接返回Entry物件,containsKey返回false或者true

keySet()

呼叫keySet()返回一個HashMap中的keySet例項。HashMap無法保證順序輸出,若要按順序,使用TreeMapHashMap非執行緒安全的。

注意要點

HashMap

1HashMap採用陣列方式儲存keyvalue構成的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非執行緒安全。