在 Java 中双波浪线(~ ~)是什么意思?

在浏览 Guava 的源代码时,我偶然发现了以下代码(内部类 CartesianSethashCode实现的一部分) :

int adjust = size() - 1;
for (int i = 0; i < axes.size(); i++) {
adjust *= 31;
adjust = ~~adjust;
// in GWT, we have to deal with integer overflow carefully
}
int hash = 1;
for (Set<E> axis : axes) {
hash = 31 * hash + (size() / axis.size() * axis.hashCode());


hash = ~~hash;
}
hash += adjust;
return ~~hash;

adjusthash都是 int。根据我对 Java 的了解,~意味着按位求负,所以 adjust = ~~adjusthash = ~~hash应该保持变量不变。运行小型测试(当然是启用断言) ,

for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
assert i == ~~i;
}

证实了这一点。假设番石榴的家伙知道他们在做什么,他们这样做一定是有原因的。问题是什么?

正如评论中指出的,上面的测试不包括 i等于 Integer.MAX_VALUE的情况。因为 i <= Integer.MAX_VALUE总是为真,所以我们需要检查循环外的那个情况,以防止它永远循环下去。但是,这条线呢

assert Integer.MAX_VALUE == ~~Integer.MAX_VALUE;

产生编译器警告“比较相同的表达式”,这很好地解决了这个问题。

18400 次浏览

在爪哇语中,这没有任何意义。

但是这条注释说这一行是专门针对 GWT 的,这是一种将 Java 编译成 JavaScript 的方法。

在 JavaScript 中,整数类似于将其作为整数的双精度函数。例如,它们的最大值为2 ^ 53。但是 按位运算符把数字看作是32位的,这正是您在这段代码中想要的。换句话说,~~hash在 JavaScript 中表示“将 hash视为32位数字”。具体来说,除了底部的32位(因为按位 ~操作符只查看底部的32位)之外,它丢弃了所有的内容,这与 Java 的溢出工作方式相同。

如果您没有这些,那么对象的哈希代码将会有所不同,这取决于它是在 Java-land 还是在 JavaScript (通过 GWT 编译)中进行计算。