我正在浏览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
值的初始化方式是否重要?
答案 0 :(得分:6)
信不信由你,它实际上是关于可读性的。表达式1 << 4
肯定不会比表达式16
更快地进行评估。另外,无论表达式是什么,都会在编译时进行评估。
使用移位表示的关键是它是表达圆二进制数的更自然的方式。初始容量的不变量以及哈希表实现中的许多其他东西,它必须是纯粹的2的幂。这更直接地与表达式1 << n
(相当于2 n )比十进制表示更直接地传达,特别是当您进入更高的n
值时(例如高于{1}}例如,16)。
答案 1 :(得分:4)
capacity
始终是2的幂(甚至指定构造函数中的容量导致调用Collections.roundUpToPowerOfTwo(capacity)
),因此以{{1 << x
的形式表示它即使您要更改x
,也可以轻松确保此限制。如果您不了解限制,其他形式在更改时会更容易搞乱
答案 2 :(得分:4)
正如您自己想象的那样,字节代码对于常数16或1&lt;&lt; 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
答案 3 :(得分:2)
下面是您问题中描述的三种初始化方法的定时测试。
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
超过16
或0x10
的唯一原因是强制初始值为2的幂。
答案 4 :(得分:2)
基本上,移位运算符用于处理位,比使用+, -
等其他运算符更快例 - 将CPU加工的两个数相乘,它将在内部执行乘法,用加法和减法代替它,它只是移位和执行AND,OR,NOT等操作。
因此,如果您直接使用位,则意味着您正在完成必须由CPU完成大量处理后的工作。
另见: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html