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獲取到有固定格式的資料,再將資料展...