Why use 1<<4 instead of 16?

前端 未结 3 793
不思量自难忘°
不思量自难忘° 2020-12-04 01:45

The OpenJDK code for java.util.HashMap includes the following line:

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


        
相关标签:
3条回答
  • 2020-12-04 02:05

    I think the reason is that the developer can very easy change the value (according to JavaDoc '/* The default initial capacity - MUST be a power of two. */') for example to 1 << 5 or 1 << 3 and he doesn't need to do any calculations.

    0 讨论(0)
  • 2020-12-04 02:10

    I can't read the developer's mind, but we do things like that to indicate a relationship between the numbers.

    Compare this:

    int day = 86400;

    vs

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

    The second example clearly shows the relationship between the numbers, and Java is smart enough to compile that as a constant.

    0 讨论(0)
  • 2020-12-04 02:17

    It's to emphasize that the number is a power of two, and not a completely arbitrary choice. It thus alerts developers experimenting with different numbers that they should use other numbers in the pattern (e.g., 1 << 3 or 1 << 5, rather than 20) so they don't break the methods which rely on the power of two requirement. There is a comment just above:

    /**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    

    The capacity (table length) of any java.util.HashMap is always a power of two. It's designed that way because that allows the use of a fast bitwise AND operation (&) to wrap each key's hash code into the range of the length of the table, as done 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
            ...
    

    There, n is the capacity, and (n - 1) & hash wraps the hash value to fit that range, selecting the appropriate bucket of the table for that hash.

    (If n were not a power of two, the formula would need to be Math.abs(hash % n), using the modulo operator to calculate the remainder after division by n, plus an extra step to deal with negative hash values. That would work, but be slower. Imagine an example in decimal, where you have some arbitrary hash value 193,498,212, and an arbitrary table length of 1,234; it's not obvious that 193498212 % 1234 happens to be 842, but with a table length that is an exact power of ten, the result of 193498212 % 1000 is simply 212, the last 3 digits. In binary, a power of two is a 1 followed by some number of 0s, so a similar trick is possible.)

    0 讨论(0)
提交回复
热议问题