首頁>Club>
各位大佬好,本人目前在培訓,遇到個問題,list介面下元素是有序的,Arraylist集合底層是陣列,linkList底層是連結串列有序,LinkedHashSet底層是增強型的連結串列,請問底層是怎麼實現排序的。看原始碼發現是比較,請問下具體是怎麼比較的?
5
回覆列表
  • 1 # 淺析架構

    1.LinkedHashSet是繼承HahsSet的,構造方法呼叫HashSet有三個引數的方法,這個構造方法底層會初始化化一個LinkedHashMap。因為LinkedHashMap是有序的,所以LinkedHashSet也是有序的。為什麼這個構造方法我們不能呼叫,因為是包訪問級別的,外部無法呼叫。接下來分析下LinkedHashMap是怎麼實現的就明白為什麼有序了。

    2.可以先看下下面的圖片。(手機上寫的問題,不能把圖片放在正文裡,全部在最下面)。

    LinkedHashMap的資料結構和HashMap就是Entry不一樣,HashMap中的Entry有四個屬性key,value,hash,next,而LinkedHashMap中的Entry添加了before和after屬性,所以說LinkedHashMap是在HashMap的基礎上使用了雙向連結串列把所有節點連起來,當然還有一個頭節點,所以遍歷的時候可以保證有序。具體結構可以看圖。

    3.LinkedHashMap主要是重寫了addEntry,createEntry方法來達到在建立節點的時候建立雙向連結串列。

    另外,LinkedHashMap還可以實現LRU演算法的快取。

    原始碼是基於JDK7看的哈。如果不理解HashMap可以看我分享的另一篇文章。

  • 2 # 此生唯一

    從原始碼的角度來對LinkedHashSet尋根問底!

    先一覽LinkedHashSet類中的所有方法,發現就是一些構造方法,沒什麼特別的。。spliterator方法也只是個迭代器!

    從構造器中的super方法點過去可得見端倪,原來構造器中的父級構造器使用的是LinkedHashMap進行例項化,那麼LinkedHashSet的特性勢必跟LinkedHashMap息息相關,換句話說LinkedHashSet的輸出有序來自於LinkedHashMap;

    下面對LinkedHashMap進行詳細分析:

    LinkedHashMap繼承HashMap,實現了Map,很明顯LinkedHashMap也算是HashMap,還儲存了陣列+連結串列的結構,至於有序的原因肯定不會是因為Map介面和繼承HashMap,也就是說LinkedHashMap的有序,肯定就是在LinkedHashMap類中實現的;

    HashMap的底層資料結構是使用陣列中的位置作為桶,每個桶中放置一份連結串列(或者紅黑樹),而hashCode落在哪一個桶是不確定的,沒有關聯關係,所以HashMap不能做到有序輸出,而LinkedHashMap使用的是雙重連結串列形式,儲存在map中的資料不僅在每一個桶裡使用連結串列維護有序,還在每個值上維護連結串列來維護有序;

    借用圖一張,如下:

    不僅如此,LinkedHashMap的迭代方式有兩種,一種是按照插入順序排序(迭代時就像佇列一樣),一種是訪問排序(像棧一樣,後訪問的放在棧頭,可作為LRU實現)

    下面分析下主要原始碼:

    1,先看LinkedHashMap中的內部類Entry:

    Entry繼承於HashMap.Node,Node物件中有hash,key,value等一個key-value結構,還有next作為hashMap中同一個桶下面的entry指向,LinkedHashMap.Entry新獲得了這些屬性,且新定義了兩個屬性Entry before, after,用來對所有的entry維護一個指向,變成一個雙向連結串列;

    其餘的諸如LinkedKeyIterator,LinkedEntrySet等內部類都是作為迭代器,

    2,再看LinkedHashMap中的屬性:

    LinkedHashMap中的主要屬性有是三個head,tail(維護連結串列的頭尾,很容易理解),accessOrder:註釋寫的很清楚,就是true的時候就是訪問順序,false的時候是插入順序;

    3,LinkedHashMap中的方法: ①,put方法:LinkedHashMap中溜了一圈,並沒發現有put方法,難道是使用的HashMap的put方法?那entry的連結串列是怎麼做到的呢?

    從HashMap中的put方法可以看到,計算了hash值之後就呼叫了putVal方法,而在生成新插入的元素的時候,使用的是newNode方法,LinkedHashMap確實沒有重寫put方法,但是重寫了newNode方法,從程式碼中可以看到HashMap中的newNode方法,只是單純的new了一個Node返回,而LinkedHashMap中的newNode方法不僅new了物件,還呼叫linkNodeLast,將物件掛在了連結串列的tail節點上,形成連結串列;(by the way,由此可見jdk中資料結構對於多型特性(重寫之後呼叫子類方法)使用的淋漓盡致)

    跟newNode方法類似的還有一個newTreeNode方法,這個也是在HashMap中的put方法裡進行呼叫的,也就是紅黑樹結構;

    ②,get方法:從get方法中可以看到,如果accessOrder為false,那麼LinkedHashMap使用的get方法和HashMap一樣,計算相應的hash值,比較key值(==,equals),匹配上則返回,如果accessOrder為true,則呼叫afterNodeAccess方法,判斷各種情況,然後把這個值設定為tail,保證是棧頭的位置,下次最先查詢到; 程式碼如上截圖!

    LinkedHashMap中的remove方法和HashMap中的是一樣的,但是最後的afterNodeRemoval方法在HashMap中的方法體是空的,而在LinkedHashMap中進行了重寫,把這個node的後一個節點接到了前一個節點上,這個node相當於脫鏈了。。 程式碼如下截圖:

    總的來說LinkedHashMap相比HashMap增加了連結串列特性,維護了元素的有序,雖然方法大部分都是用的HashMap的方法,但是使用重寫這種多型特性,在LinkedHashMap中進行了不同了實現,可以說這也是我們開發程式碼時應該要學習的,以後再擴充套件其他型別的HashMap,只用重寫部分方法即可實現!

    LinkedHashMap就說到這,筆者已經分享了很多java方面的技術,有很多幫助到了一些朋友!還會一直持續分享,敬請關注。。。

  • 中秋節和大豐收的關聯?
  • 喬家大院為什麼要建成“囍”字形狀?