java集合派系學習

一、collection派系

1.1 set 無重複

treeset有序set,底層是treemap,插入數據存在map的key位置,value是固定值。

hashset底層是hashmap,同樣插入數據存在map的key位置,value是固定值。

 

1.2 list 可重複

arrayList的類圖如下:

底層結構,capacity默認長度,默認10

添加:elementData()存儲具體的元素,他的默認無參構造函數是懶初始化的,在add時才初始化,在add時首先元素增長1然後判斷elementData空間是否夠,夠了直接存放,不夠就擴容(擴容完對數組進行復制拷貝,從而完成初始化),每次擴容變成原來的1.5倍長。

查找:先檢查數組越界,數組的下標直接訪問

刪除:刪除後,後續所有節點會全部移動位置,首先計算要移動的數量,做數組的拷貝,然後將最後一個數組元素置爲null,由gc回收。

modcount:其實就是版本記錄器,當多線程併發訪問同一個list時,版本不一致的話直接失敗。

LinkList

deque雙端隊列

屬性:Node first 頭節點;Node last尾節點;size大小;其中Node是內部類

增:add()尾部直接插入元素,add(index):首先使用二分找到index對應的node直接在該位置插入即可。

刪:remove()刪除頭,remove(index);

查:get(index):先檢查越界,然後通過判斷index和size/2的大小比較,小則從頭遍歷,否則從尾遍歷。

 

集合多線程安全

vector線程安全的。底層原理和arraylist差不多,動態擴容等

在add()方法上加了一個synchronized,同理remove方法上也加了這個鎖。

第一種就是加鎖,第二種工具類,Collections.synchronizedList(),可以將list轉爲一個多線程安全的SynchronizedList;

SynchronizedList的增刪都加了鎖,所以線程安全的。

 

二、map派系

2.1 HashMap

屬性:size,Node內部類,entrySet,modcount版本號,TREEIFY_THRESHOLD=8即當連表個數大於8時轉爲紅黑樹,紅黑樹不足8時轉化爲鏈表,DEFAULT_LOAD_FACTOR=0.75計算因子,。

增:一搬分兩個階段,1先找到插入位置,然後在連表或紅黑樹上插入;

第一階段:(用key的hashcode與數組長度取模運算得到具體位置),其實hashmap並不是與數組長度取餘,而是用key的hashcode與數組長度-1的值做與運算。所以數組的長度必須是2的n次冪。

put(K,V):resize雙倍擴容或第一次的初始化操作。首先用一階段找到位置,若位置無值直接創建node存放即可,若果有值且是連表直接在連表尾部插入,如果是紅黑樹則需要紅黑樹的插入。

查:get(Key):首先根據key的hashcode確定數組位置,然後根據數組位置,直接返回數組值或繼續查找連表或繼續查找紅黑樹。

動態擴容:

1,什麼時候擴容?當++size()>數組長度*平衡因子,則創建比old array兩倍大的新數組,並重新計算位置將老的數據複製過去。擴容後元素的位置,要麼還是在原來位置,要麼是在原來位置+oldArray.length,如,index=17;oldArray=16,newArray=31,所以在oldArray的1位置,到新數組後變成了17位置。即index&oldArray.length==0(最高位是不是1來判斷),位置不變,否者位置變爲加oldArray.length後的位置,所以一個連表可能變成兩個連表。

hash與int的最大值,然後和數組長度取模。而hashmap是與數組長度-1的值,hashtable基本不用了。

 

TreeMap底層是紅黑樹,爲什麼不使用AVL平衡二叉樹呢,查詢效率更高,是因爲數據插入10次(1到10),AVL調整6次,而紅黑樹調整5次。再做增刪調整樹會浪費很大的性能,所以選擇了紅黑樹。

屬性:Comparator默認自然排序比較器;Entry<K,V> root樹的根節點,Entry就是紅黑樹節點有key,value,left,right,parent,以及isRed;size個數,modcount版本號;

put(K,V):先比較當前節點的key和插入的key用比較器比較;用比較器採用遞歸的二分查找,找到位置插入。

get(K): 用比較器二分查找。

 

三、兩大派系關係如下,相輔相成

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章