java.util.HashMap
的OpenJDK代码包括以下行:
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
为什么1 << 4
在这里使用,而不是16
?我很好奇。
需要强调的是,这个数字是2的幂,而不是完全随意的选择。因此,它提醒开发人员尝试不同的数字,他们应该使用模式中的其他数字(例如,1 << 3
或1 << 5
,而不是20
),因此他们不会破坏依赖于两个要求的力量的方法。有一个评论just above:
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
任何java.util.HashMap
的容量(表长度)总是2的幂。它的设计方式是因为它允许使用快速按位AND运算(&
)将每个键的哈希码包装到表的长度范围内,如in methods that access the table所做:
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) { /// <-- bitwise 'AND' here
...
在那里,n
是容量,(n - 1) & hash
包装哈希值以适应该范围,为该哈希选择适当的表桶。
(如果n
不是2的幂,那么公式需要是Math.abs(hash % n)
,使用模运算符来计算n
除法后的余数,加上一个额外的步骤来处理负哈希值。这会起作用,但要慢一些。想象一个十进制的例子,你有一些任意哈希值193,498,212,任意表长度为1,234; 193498212 % 1234
恰好是842并不明显,但是表长度是10的精确幂,193498212 % 1000
的结果简单地说就是212,最后3位数。在二进制中,2的幂是1然后是0的一些数,所以类似的技巧是可能的。)
我无法读懂开发人员的想法,但我们会这样做以表明数字之间的关系。
比较一下:
int day = 86400;
VS
int day = 60 * 60 * 24; // 86400
第二个例子清楚地显示了数字之间的关系,而Java足够聪明,可以将其编译为常量。
我认为原因是开发人员可以很容易地更改值(根据JavaDoc'/ *默认初始容量 - 必须是2的幂。* /')例如1 << 5
或1 << 3
他不需要做任何计算。