面試中的Collection集合 原始碼分析

2021-10-02 00:10:45 字數 3208 閱讀 9245

collection介面:單列集合,用來儲存乙個乙個的物件

1,list介面:儲存有序的,可重複的資料。 -->「動態」陣列,替換原有的陣列

2,arraylist:作為list介面的主要實現類,執行緒不安全,效率高,底層使用object elementdata儲存

2.1,arraylist的原始碼分析:jdk7

arraylist list =

newarraylist()

;//底層建立了長度是10的object陣列elementdata

list.

add(

123)

;//elementdata[0] = new integer(123);..

.list.

add(11)

;//如果此次的新增導致底層elementdata陣列陣列容量不夠,則擴容。預設情況下,擴容為原來的容量的1.5倍,同時需要將原有的資料複製到新的陣列中。

結論:建議開發中使用帶參的構造器:arraylist list = new arraylist(int capacity)

2.2,jdk8 中arraylist的變化:

arraylist list =

newarraylist()

;//底層object elementdata初始化為{},並沒有建立長度為10的陣列

list.

add(

123)

;//第一次呼叫add()時,底層才建立了長度10的陣列,並將123新增到elementdata中去

//後續的新增和擴容操作與jdk 7無異

結論:jdk7中的arraylist的物件的建立類似於單例的餓漢式,而jdk8中的arraylist的物件的建立類似於單例的懶漢式,延遲了陣列的建立,節省記憶體。

3,linkedlist:對於頻繁的插入,刪除操作,使用此類效率比arraylist高;底層使用雙向鍊錶儲存

3.1,linkedlist的原始碼分析:

linkedlist list =

newlinkedlist()

;內部宣告了node型別的first和last屬性,預設值為null

list.

add(

123)

;//將123封裝到node中,建立了node物件。

其中,node定義為:體現了linkedlist的雙向鍊錶的說法

e item;

node

next;

node

prev;

node

(node

prev, e element, node

next)

4,vector:作為list介面的古老實現類,執行緒安全的,效率低,底層使用object elementdata儲存

4.1,vector的原始碼分析

jdk7和jdk8中通過vector()構造器建立物件時,底層都建立了長度為10的陣列,在擴容方面,預設擴容為原來的陣列長度的2倍

set介面:儲存無序的,不可重複的資料

1,hashset: 作為set介面的主要實現類,執行緒不安全的,可以儲存null值

2,linkedhashset:作為hashset的子類:遍歷其內部資料時,可以按照新增的順序遍歷。對於頻繁的遍歷操作,linkedhashset效率高於hashset.

3,treeset: 可以按照新增物件的指定屬性

3.1treeset:

1,向treeset中新增的資料,要求是相同類的物件

2,兩種排序方式:自然排序(實現comparable介面)和定製排序(comparator)

3,自然排序中,比較兩個物件是否相同的標準為:compareto()返回0,不再是equals()。

4,定製排序中,比較兩個物件是否相同的標準為:compare()返回0,不再是equals()。

set原始碼分析

set中無序性: 不等於隨機性。儲存的資料在底層資料中並非按照陣列所以的順序新增,而是根據資料的雜湊值決定的

不可重複性: 保證新增元素按照equals()判斷時,不能返回true。即:相同的元素只能新增乙個

新增元素的過程: 以hashset(陣列+鍊錶)為例:

我們向hashset中新增元素a,首先呼叫元素a所在的hashcode()方法,計算元素a的雜湊值,此雜湊值接著通過某種演算法計算出在hashset底層陣列中的存放位置(即為索引位置),判斷陣列此位置上是否已經有元素:

情況1 --> 如果此位置上沒有其他元素,則元素a新增成功。

如果此位置上有其他元素b(或以鍊錶形式存在的多個元素),則比較元素a與元素b的hash值:

情況2 -->         如果hash值不相同,則元素a新增成功。

如果hash值相同,進而需要呼叫元素a所在類的equals()方法:

equals()方法返回true,元素a新增失敗。

情況3 -->             equals()方法返回false,則元素a新增成功。

對於新增成功的情況2和情況3而言:元素a與已經存在指定索引位置上資料以鍊錶的方式儲存。

jdk7:元素a放到陣列中,指向原來的元素。

jdk8:原來的元素在陣列中,指向元素a

總結:七上八下

4.1 set介面中沒有額外定義新的方法,使用的都是collection中宣告過的方法。

4.2 要求:

重寫的hashcode()和equals()盡可能保持一致性:相等的物件必須具有相等的雜湊碼

重寫兩個方法的小技巧:物件中用作equals()方法比較的field,都應該用來計算hashcode值

為什麼重寫hashcode方法,有31這個數字?

1,選擇係數的時候要選擇盡量大的係數,因為如果計算出來的hash位址越大,所謂的"衝突"就越少,查詢起來效率也會提高。(減少衝突)

2,並且31只占用5bits,相乘造成資料溢位的概率較小。

3,31可以由i*31 == (i << 5)-1來表示,現在很多虛擬機器裡面都有做相關優化。(提高演算法效率)

4,31是乙個素數,素數作用就是如果我用乙個數字來乘以這個素數,那麼最終出來的結果只能被素數本身和被乘數還有1來整除!(減少衝突)

Collection集合的子類List集合

1.因為list集合是collection的子類,所以他可以呼叫collection集合中的所有方法。2.list集合特有方法的概述 void add int index,e element 在指定索引處新增元素 e remove int index 移除指定索引處的元素,返回的是移除的元素 e g...

Collection中的排序

我們來了解一下collection的框架與介面 set介面下面已經有sortedset介面,其中提供了很多自帶排序的實現類,例如threeset,使用者還能夠自定義比較器來規定自己的排序規則。本篇著重說list介面下的排序,list的排序主要通過服務於collection框架的工具類collecti...

Collection集合框架和List集合筆記

1.什麼是集合?能夠儲存多個同型別的基本資料型別的容器我們叫陣列,那麼可以儲存多個同型別物件的容器我們就稱之為集合!什麼是collection集合框架,通過下面這個圖來說明!collection是乙個根介面,而它旗下又很多個子介面繼承了它,其中兩個最重要的子介面分別的是list和set,它們繼承了c...