HashMap 源码解析一、构造函数,kotlin 插件
前两个没什么好讲的,我们直接看第 3 个 HashMap(int initialCapacity, float loadFactor)
这里的重点就是 int tableSizeFor(int cap)函数。
tableSizeFor(int cap) 函数
tableSizeFor(int cap) 的作用是返回 大于等于 cap 且 最接近 cap 的 2 的幂次方的值
static final int MAXIMUM_CAPACITY = 1 << 30;/**
Returns a power of two size for the given ta
rget capacity.
返回 大于等于 cap 且 最接近 cap 的 2 的幂次方的值*/static final int tableSizeFor(int cap) {int n = cap - 1;n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}
我们分步骤解析一下这个函数:
>>>
无符号右移运算符,高位用 0 填充。如下:
a = 1010a >>> 1 = 0101
|
如果相对应位都是 0,则结果为 0,否则为 1。如下:
a = 1010b = 0011
a | b = 1011
|=
,a |= b
等同于a = a|b
。
这时候我们就能看懂 n |= n >>> 1
; 等同于 n = n | n >>> 1
int n = cap - 1;
是因为如果 cap 不减 1,当 cap 本来就是 2 次幂数值,就会导致返回的结果为 cap*2 。我们带入一个值看下运行结果,假设 cap = 20
static final int tableSizeFor(int cap) {System.out.println("cap = "+ Integer.toBinaryString(cap));int n = cap - 1;System.out.println("n = "+ Integer.toBinaryString(n));n |= n >>> 1;System.out.println("n1 = "+ Integer.toBinaryString(n));n |= n >>> 2;System.out.println("n2 = "+ Integer.toBinaryString(n));n |= n >>> 4;System.out.println("n4 = "+ Integer.toBinaryString(n));n |= n >>> 8;System.out.println("n8 = "+ Integer.toBinaryString(n));n |= n >>> 16;System.out.println("n16 = "+ Integer.toBinaryString(n));System.out.println("n+1 = "+ Integer.toBinaryString(n+1));return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}
@Testpublic void tableSizeForTest(){System.out.println("tableSizeFor:"+ tableSizeFor(20));}
我这里直接把 tableSizeFor(int cap) 拷贝出来,然后添加了日志。结果如下:
cap = 10100n = 10011n1 = 11011 (10011 | 01001)n2 = 11111 (11011 | 01101)n4 = 11111 (11111 | 01111)n8 = 11111 (11111 | 01111)n16 = 11111 (11111 | 01111)n+1 = 100000 (11111 + 1)tableSizeFor:32
HashMap(Map<? extends K, ? extends V> m) 构造函数
我们来看下最后一个构造函数,参数是一个 Map ,loadFactor 设置为默认的 0.75,然后 putMapEntries(m, false) 函数,把参数 Map 的值拷贝到构造的 HashMap 中去。
接着我们看下 putMapEntries(m, false) 这个函数的具体实现
putMapEntries(m, false) 函数
/**
在 putAll 和 构造函数 中被调用
@param m the map
@param 构造函数调用是传 false,否则传 true*/final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {int s = m.size();if (s > 0) {if (table == null) { // 构造函数调用是 table = nullfloat ft = ((float)s / loadFactor) + 1.0F;int t = ((ft < (float)MAXIMUM_CAPACITY) ?(int)ft : MAXIMUM_CAPACITY);if (t > threshold)
评论