对于HashMap内的所有实现来说,首先第一步是定位对键值对所在数组的索引下标位置,这是后续所有操作的基础.
如下代码是展示索引下标获取的基本逻辑:
/* ---------------- Static utilities -------------- *//*** Computes key.hashCode() and spreads (XORs) higher bits of hash* to lower. Because the table uses power-of-two masking, sets of* hashes that vary only in bits above the current mask will* always collide. (Among known examples are sets of Float keys* holding consecutive whole numbers in small tables.) So we* apply a transform that spreads the impact of higher bits* downward. There is a tradeoff between speed, utility, and* quality of bit-spreading. Because many common sets of hashes* are already reasonably distributed (so don't benefit from* spreading), and because we use trees to handle large sets of* collisions in bins, we just XOR some shifted bits in the* cheapest possible way to reduce systematic lossage, as well as* to incorporate impact of the highest bits that would otherwise* never be used in index calculations because of table bounds.*/static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
然后, 数组元素的下标算法是:
public static final int index(int hash, int n) {return (n - 1) & hash;}
代码拆解:
public static final int hash(Object key) {if (key == null) {return 0;}int h = key.hashCode();int rh = h >>> 16;out.println("===================== hash(" + key + ") ===========================");out.println("key \t\t" + key);out.println("h=key.hashCode() \t\t" + toBinary(h) + "\t\t" + h);out.println("rh=h>>>16 \t\t" + toBinary(rh) + "\t\t" + rh);return h ^ rh;}public static final int index(int hash, int n) {out.println("hash=h ^ rh \t\t" + toBinary(hash) + "\t\t" + hash);out.println("n = \t\t" + toBinary(n) + "\t\t" + (n));out.println("n - 1= \t\t" + toBinary(n - 1) + "\t\t" + (n - 1));int index = (n - 1) & hash;out.println("index=(n - 1) & hash \t\t" + toBinary(index) + "\t\t" + index);out.println();return index;}
运行测试数据:
===================== hash(a) ===========================
key a
h=key.hashCode() 00000000000000000000000001100001 97
rh=h>>>16 00000000000000000000000000000000 0
hash(a)=97
hash=h ^ rh 00000000000000000000000001100001 97
n = 00000000000000000000000000000001 1
n - 1= 00000000000000000000000000000000 0
index=(n - 1) & hash 00000000000000000000000000000000 0===================== hash(b) ===========================
key b
h=key.hashCode() 00000000000000000000000001100010 98
rh=h>>>16 00000000000000000000000000000000 0
hash(b)=98
hash=h ^ rh 00000000000000000000000001100010 98
n = 00000000000000000000000000000010 2
n - 1= 00000000000000000000000000000001 1
index=(n - 1) & hash 00000000000000000000000000000000 0===================== hash(abc) ===========================
key abc
h=key.hashCode() 00000000000000010111100001100010 96354
rh=h>>>16 00000000000000000000000000000001 1
hash(abc)=96355
hash=h ^ rh 00000000000000010111100001100011 96355
n = 00000000000000000000000000000100 4
n - 1= 00000000000000000000000000000011 3
index=(n - 1) & hash 00000000000000000000000000000011 3===================== hash(abcde) ===========================
key abcde
h=key.hashCode() 00000101100001001111010001100011 92599395
rh=h>>>16 00000000000000000000010110000100 1412
hash(abcde)=92598759
hash=h ^ rh 00000101100001001111000111100111 92598759
n = 00000000000000000000000000001000 8
n - 1= 00000000000000000000000000000111 7
index=(n - 1) & hash 00000000000000000000000000000111 7===================== hash(abcdefg) ===========================
key abcdefg
h=key.hashCode() 10111000000110010111010001100100 -1206291356
rh=h>>>16 00000000000000001011100000011001 47129
hash(abcdefg)=-1206268803
hash=h ^ rh 10111000000110011100110001111101 -1206268803
n = 00000000000000000000000000001000 8
n - 1= 00000000000000000000000000000111 7
index=(n - 1) & hash 00000000000000000000000000000101 5
算法图解:
源码分析:
More formally, if this map contains a mapping from a key* {@code k} to a value {@code v} such that {@code (key==null ? k==null :* key.equals(k))}, then this method returns {@code v}; otherwise* it returns {@code null}. (There can be at most one such mapping.)** A return value of {@code null} does not necessarily* indicate that the map contains no mapping for the key; it's also* possible that the map explicitly maps the key to {@code null}.* The {@link #containsKey containsKey} operation may be used to* distinguish these two cases.** @see #put(Object, Object)*/public V get(Object key) {Node /*** Returns the value to which the specified key is mapped,* or {@code null} if this map contains no mapping for the key.**
输入: int cap;
返回: n = tableSizeFor(cap)
其中, n % 2 &#61;&#61;0, and cap <&#61;n.
/*** Returns a power of two size for the given target capacity.*/static final int tableSizeFor(int cap) {// 先 cap 减 1int n &#61; cap - 1;n |&#61; n >>> 1;n |&#61; n >>> 2;n |&#61; n >>> 4;n |&#61; n >>> 8;n |&#61; n >>> 16;return (n <0) ? 1 : (n >&#61; MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n &#43; 1; // 再加 1}
我们来运行测试一下:
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;tableSizeFor(2)&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
cap &#61; 2
n &#61; cap - 1 00000000000000000000000000000001
n &#61; n | (n >>> 1) 00000000000000000000000000000001
n &#61; n | (n >>> 2) 00000000000000000000000000000001
n &#61; n | (n >>> 4) 00000000000000000000000000000001
n &#61; n | (n >>> 8) 00000000000000000000000000000001
n &#61; n | (n >>> 16) 00000000000000000000000000000001
tableSizeFor &#61; 2
2
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;tableSizeFor(5)&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
cap &#61; 5
n &#61; cap - 1 00000000000000000000000000000100
n &#61; n | (n >>> 1) 00000000000000000000000000000110
n &#61; n | (n >>> 2) 00000000000000000000000000000111
n &#61; n | (n >>> 4) 00000000000000000000000000000111
n &#61; n | (n >>> 8) 00000000000000000000000000000111
n &#61; n | (n >>> 16) 00000000000000000000000000000111
tableSizeFor &#61; 8
8
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;tableSizeFor(10)&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
cap &#61; 10
n &#61; cap - 1 00000000000000000000000000001001
n &#61; n | (n >>> 1) 00000000000000000000000000001101
n &#61; n | (n >>> 2) 00000000000000000000000000001111
n &#61; n | (n >>> 4) 00000000000000000000000000001111
n &#61; n | (n >>> 8) 00000000000000000000000000001111
n &#61; n | (n >>> 16) 00000000000000000000000000001111
tableSizeFor &#61; 16
16
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;tableSizeFor(25)&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
cap &#61; 25
n &#61; cap - 1 00000000000000000000000000011000
n &#61; n | (n >>> 1) 00000000000000000000000000011100
n &#61; n | (n >>> 2) 00000000000000000000000000011111
n &#61; n | (n >>> 4) 00000000000000000000000000011111
n &#61; n | (n >>> 8) 00000000000000000000000000011111
n &#61; n | (n >>> 16) 00000000000000000000000000011111
tableSizeFor &#61; 32
32
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;tableSizeFor(58)&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
cap &#61; 58
n &#61; cap - 1 00000000000000000000000000111001
n &#61; n | (n >>> 1) 00000000000000000000000000111101
n &#61; n | (n >>> 2) 00000000000000000000000000111111
n &#61; n | (n >>> 4) 00000000000000000000000000111111
n &#61; n | (n >>> 8) 00000000000000000000000000111111
n &#61; n | (n >>> 16) 00000000000000000000000000111111
tableSizeFor &#61; 64
64
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;tableSizeFor(100)&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
cap &#61; 100
n &#61; cap - 1 00000000000000000000000001100011
n &#61; n | (n >>> 1) 00000000000000000000000001110011
n &#61; n | (n >>> 2) 00000000000000000000000001111111
n &#61; n | (n >>> 4) 00000000000000000000000001111111
n &#61; n | (n >>> 8) 00000000000000000000000001111111
n &#61; n | (n >>> 16) 00000000000000000000000001111111
tableSizeFor &#61; 128
128
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;tableSizeFor(896)&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
cap &#61; 896
n &#61; cap - 1 00000000000000000000001101111111
n &#61; n | (n >>> 1) 00000000000000000000001111111111
n &#61; n | (n >>> 2) 00000000000000000000001111111111
n &#61; n | (n >>> 4) 00000000000000000000001111111111
n &#61; n | (n >>> 8) 00000000000000000000001111111111
n &#61; n | (n >>> 16) 00000000000000000000001111111111
tableSizeFor &#61; 1024
1024
&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;tableSizeFor(1073741000)&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
cap &#61; 1073741000
n &#61; cap - 1 00111111111111111111110011000111
n &#61; n | (n >>> 1) 00111111111111111111111011100111
n &#61; n | (n >>> 2) 00111111111111111111111111111111
n &#61; n | (n >>> 4) 00111111111111111111111111111111
n &#61; n | (n >>> 8) 00111111111111111111111111111111
n &#61; n | (n >>> 16) 00111111111111111111111111111111
tableSizeFor &#61; 1073741824
1073741824
参考资料
https://blog.csdn.net/fan2012huan/article/details/51097331
https://www.jianshu.com/p/cbe3f22793be
https://www.jianshu.com/p/dbbecc36200d
国内第一Kotlin 开发者社区公众号&#xff0c;主要分享、交流 Kotlin 编程语言、Spring Boot、Android、React.js/Node.js、函数式编程、编程思想等相关主题。
越是喧嚣的世界&#xff0c;越需要宁静的思考。