使用按位运算或数字文字来初始化值是否更快?

Is it faster to initialize a value with a bitwise operation or a numeric literal?

我正在浏览 HashMap 的源代码。我看到了类似的东西 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16. 我想知道他们为什么使用移位运算符。这会加快计算速度吗?所以我寻找了这三个操作之间的 byte 差异:

int DEFAULT_INITIAL_CAPACITY =  0x10;
L0
    LINENUMBER 52 L0
    BIPUSH 16
    ISTORE 1



int DEFAULT_INITIAL_CAPACITY1 =  1 << 4;
  L1
    LINENUMBER 54 L1
    BIPUSH 16
    ISTORE 2

int test = 16;
 L2
    LINENUMBER 56 L2
    BIPUSH 16
    ISTORE 3

值的初始化方式重要吗?

从速度的角度来看,这可能不是优势。然而,看起来 HashMap 的 capacity 总是 2 的幂(即使在构造函数中指定容量也会导致调用 Collections.roundUpToPowerOfTwo(capacity)),因此以 1 << x 的形式表示它确保这个限制很简单,即使你要改变 x。如果您不知道限制,其他表格在更改时会更容易搞砸

正如您自己发现的,字节码对于常量 16 或 1 << 4 是相同的。在这种特殊情况下,我认为这只是一个可读性问题:强调初始容量应该是 2 的幂(通过将 1 向左移动,您只能获得 2 的幂)。这是我在 HashMap 的源代码中的内容:

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

信不信由你,这实际上是关于可读性的。表达式 1 << 4 的计算速度肯定不会比表达式 16 快。另外,无论表达式是什么,它都会在编译时求值。

使用移位表示的要点是它是一种更自然的表示循环二进制数的方式。初始容量的不变性,以及哈希表实现中的许多其他事物,是它必须是 2 的纯幂。与十进制表示相比,表达式 1 << n(相当于 2n)更直接地传达了这一点,尤其是当您进入 n 的更高值时(例如例如,任何高于 16 的值)。

下面是对你问题中描述的三种初始化方法的定时测试。

public static void main(String[] args) {
    
    long time = System.currentTimeMillis();
    int test = 0;
    for(int i = 0; i < 100000; i++){
        test = 16;
    }
    
    System.out.println((System.currentTimeMillis() - time) + " : " + test);
    
    time = System.currentTimeMillis();
    int test2 = 0;
    for(int i = 0; i < 100000; i++){
        test2 = 1 << 4;
    }
    
    System.out.println((System.currentTimeMillis() - time) + " : " + test2);
    
    time = System.currentTimeMillis();
    int test3 = 0;
    for(int i = 0; i < 100000; i++){
        test3 = 0x10;
    }
    
    System.out.println((System.currentTimeMillis() - time) + " : " + test3);
}

运行 这会产生

2 : 16

2 : 16

2 : 16

每次执行的时间为 + 或 - 5 毫秒。这表明值的初始化方式几乎无关紧要。

结论:

使用哪种方法初始化值没有程序化区别。

似乎使用 1 << 4 而不是 160x10 的唯一原因是强制初始值是 2 的幂。

基本上,移位运算符用于处理位,并且比处理 +、- 等其他运算符更快

例子- 将两个数字相乘,CPU 会在内部执行乘法运算,将其替换为加法和减法,它只不过是对位进行移位和执行 AND、OR、NOT 等运算。

因此,如果您直接在位上工作,则意味着您正在做 CPU 经过大量处理后必须完成的工作。

另见: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html