3. Key的設計
對於String型的Key,如果無法保證無沖突而且能用==來對比,那就盡量搞短點,否則一個個字符的equals還是花時間的。
甚至,對於已知的預定義Key,可以自己試着放一下,看沖不沖突。比如,像”a1”,”a2”,”a3” 這種,hashCode是個小數字遞增,絕對是不沖突的:)
4. EnumMap
對於上面的問題,有些同學可能會很沖動的想,這么麻煩,我還是換回用數組,然后用常量來定義一些下標算了。其實不用自己來,EnumMap就是可讀性與性能俱佳的實現。
EnumMap的原理是,在構造函數里要傳入枚舉類,那它就構建一個與枚舉的所有值等大的數組,按Enum. ordinal()下標來訪問數組,不就是你剛才想做的事情么?
美中不足的是,因為要實現Map接口,而 V get(Object key)中key是Object而不是泛型K,所以安全起見,EnumMap每次訪問都要先對Key進行類型判斷。在JMC里錄得不低的采樣命中頻率。
所以也可以自己再port一個類出來,不實現Map接口,或者自己增加fastGet(),fastPut()的函數。
5. IntObjectHashMap
Netty以及其他FastUtils之類的原始類型map,都支持key是int或 long。但兩者的區別並不僅僅在於int 換 Integer的那點空間,而是整個存儲結構和Hash沖突的解決方法都不一樣。
HashMap的結構是 Node[] table; Node 下面有Hash,Key,Value,Next四個屬性。
而IntObjectHashMap的結構是int[] keys 和 Object[] values.
在插入時,同樣把int先取模落桶,如果遇到沖突,則不采樣HashMap的鏈地址法,而是用開放地址法(線性探測法)index+1找下一個空桶,最后在keys[index],values[index]中分別記錄。在查找時也是先落桶,然后在key[index++]中逐個比較key。
所以,對比整個數據結構,省的不止是int vs Integer,還有每個Node的內容。
而性能嘛,IntObjectHashMap還是穩贏一點的,隨便測了幾種場景,耗時至少都有24ms vs 28ms的樣子,好的時候甚至快1/3。
優化建議:
1.考慮加載因子地設定初始大小
2.減小加載因子
3.String類型的Key,不能用==判斷或者可能有哈希沖突時,盡量減少長度。
4.使用定制版的EnumMap
5.使用IntObjectHashMap