你真的了解LinkedHashMap嗎?進來看看

2021-10-18 16:18:37 字數 4125 閱讀 2434

linkedhashmap 繼承於 hashmap,因此,建議在學習本篇內容前,先學習 hashmap系列,這樣使得更加容易理解。

可能很多人會說,linkedhashmap誰不會用?你真的確定你會用?

上例子之前,先寫幾個工具方法,以便後面理解方便:

public class main 

// 反射獲取 hashmap 中的陣列物件

// 啥?你不知道陣列物件名稱?

// 建議去看看原始碼,或是看看我寫的 hashmap 系列

private static map.entry getarray(object object, field field) throws exception

// 反射獲取 map.entry

// 因為 hashmap.node 是私有靜態類

private static map.entrygetobject(object object, string name) throws exception

// 反射獲取指定字段

private static field getfield(class> clazz, string name)

field field = null;

try catch (nosuchfieldexception e)

return field;}}

好了,上面的工具方法已經完成,後面的所有例子都會使用上面的方法。

我們來看兩個例子:

public class main  else if (after == null)  else 

system.out.println("[" + i + "] => " + spacefill(table[i]) + ", before => " + spacefill(before) + ", after => " + spacefill(after));}}

} catch (exception e) }}

}

輸出結果:

this is head [1] => 1=chris             , before => null                , after => 2=qingye            

[2] => 2=qingye , before => 1=chris , after => [email protected]

this is tail [3] => [email protected] , before => 2=qingye , after => null

public class main  else if (after == null)  else 

system.out.println("[" + i + "] => " + spacefill(table[i]) + ", before => " + spacefill(before) + ", after => " + spacefill(after));}}

} catch (exception e) }}

}

輸出結果:

this is tail [1] => 1=chris             , before => [email protected]   , after => null                

this is head [2] => 2=qingye , before => null , after => [email protected]

[3] => [email protected] , before => 2=qingye , after => 1=chris

wtf ?!發生了啥?怎麼[1]元素從『head』變成了『tail』? 這就是 linkedhashmap 的其妙之處!

本篇開頭也說了,前者繼承於後者,因此,linkedhashmap 的 put*** 和 get*** 都直接繼承於 hashmap,並沒有過載,其 put & get 的邏輯也就和 hashmap 一樣。hashmap 的 put & get 是啥邏輯?如果大家忘記了,建議去看看我寫的 (四)hashmap系列:put元素(不看完將後悔一生!) 。既然是繼承,同樣的,它們的陣列結構也就幾乎一致(99%的一致):

資料結構:陣列 + 鍊錶 紅黑樹

那 1% 的不一致在哪?

hashmap 的節點實現了 map.entry:

public class hashmapextends abstractmapimplements map, cloneable, serializable 

}

那 linkedhashmap的節點呢?

public class linkedhashmapextends hashmapimplements map}}

額,真是簡單的令人髮指啊! 僅僅多了兩個索引(指標)節點:before & after !

之前再講 hashmap 時,並沒有提到 treenode 這個型別,因為涉及到 linkedhashmap,所以有所調整,這裡進行補充:

public class hashmapextends abstractmapimplements map, cloneable, serializable 

}

完美的繼承:

根據這兩個欄位的名稱,我們就能很容易的猜測出,分別指向前乙個節點和後乙個節點(事實上,我們開頭的兩個例子,已經證實了這種關係),那麼,具體是如何在資料結構或者說,節點物件上表現出關聯關係的呢?

畫圖很辛苦… linkedhashmap 之所以加了 before 與 after 節點索引,主要目的:

/**

* the iteration ordering method for this linked hash map: true for access-order, false for insertion-order.

*/final boolean accessorder;

該欄位含義:

android系統中的 lru 的實現,其實就是基於 linkedhashmap,並採用了【例子二】的方式來初始化物件例項。

我們同樣從 put元素還是分析原始碼,還記得我們分析 hashmap 的 putval 時,有兩個空函式麼?

public class hashmapextends abstractmapimplements map, cloneable, serializable 

}......

afternodeinsertion(evict); // 新增元素,調整節點順序

return null;}}

該方法會被多個其它方法觸發,例如:put乙個已存在的節點物件,get物件,replace物件等等,該方法就是判斷是否需要調整的遍歷訪問順序。

public class linkedhashmapextends hashmapimplements map

tail = p; // 最後,尾指向最後乙個元素

++modcount;}}

}

public class linkedhashmapextends hashmapimplements map}}

5.3、linkedhashmap.removeeldestentry

public class linkedhashmapextends hashmapimplements map

}

那為啥我還一直提到 lru 呢? 因為,我們如果自己基於 linkedhashmap 來實現 lru,就可以過載此方法,返回 true ,這樣就達到了 lru 的效果。

好了,linkedhashmap 就聊到這裡!

你真的了解Java嗎?

三目運算子規則 如果第二個和第三個運算元具有相同的型別,那麼它就是條件表示式的類 型。換句話說,你可以通過繞過混合型別的計算來避免 煩。如果乙個運算元的型別是 t,t 表示 byte short 或 char,而另乙個運算元是乙個 int 型別的常量表示式,它的值是可以用型別 t 表示的,那麼條件表...

你真的了解sizeof 麼?

sizeof並不是c語言和c 語言中的乙個函式,而是乙個關鍵字,乙個操作符。它的作用是返回乙個物件或者型別名的長度,也就是說這個物件或者型別所佔的記憶體位元組數。它的返回值型別為size t usinged int 長度的單位是位元組。1 對基本資料型別運用sizeof操作,得到其占用記憶體的位元組...

你真的了解restful api嗎?

在以前,乙個 的完成總是 all in one 頁面,資料,渲染全部在服務端完成,這樣做的最大的弊端是後期維護,擴充套件極其痛苦,開發人員必須同時具備前後端知識。於是慢慢的後來興起了前後端分離的思想 後端負責資料編造,而前端則負責資料渲染,前端靜態頁面呼叫指定api獲取到有固定格式的資料,再將資料展...