为什么使用1<<< 4而不是16?

时间:2016-03-16 15:20:25

标签: java openjdk

java.util.HashMap的OpenJDK代码包含以下行:

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

为什么1 << 4在这里使用,而不是16?我很好奇。

3 个答案:

答案 0 :(得分:21)

要强调的是,这个数字是2的幂,而不是完全随意的选择。因此,它提醒开发人员尝试使用不同的数字,他们应该使用模式中的其他数字(例如,1 << 31 << 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后的余数,再加上一步处理负散列值。这会起作用,但要慢一些。想象一下 decimal 中的一个例子,你有一些任意散列值193,498,212,任意表长度为1,234;这一点并不明显{ {1}}恰好是842,但是表长度是 10 的精确幂,193498212 % 1234的结果只是212,最后3位。在二进制 2 的幂是一个1后跟一些0,所以类似的技巧是可能的。)

答案 1 :(得分:10)

我无法理解开发人员的想法,但我们会做这样的事情来表明数字之间的关系。

比较一下:

int day = 86400;

VS

int day = 60 * 60 * 24; // 86400

第二个例子清楚地显示了数字之间的关系,而Java足够聪明,可以将其编译为常量。

答案 2 :(得分:0)

我认为原因是开发人员可以很容易地更改值(根据JavaDoc'/ *默认初始容量 - 必须是2的幂。* /')例如1 << 5或{ {1}}并且他不需要做任何计算。