Просматривая исходный код Guava, я наткнулся на следующий фрагмент кода (часть реализации hashCode
для внутреннего класса CartesianSet
):
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;
Оба adjust
и hash
являются int
s. Из того, что я знаю о Java, ~
подразумевается побитовое отрицание, поэтому adjust = ~~adjust
и hash = ~~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;
выдает предупреждение компилятора «Сравнение идентичных выражений», которое в значительной степени его прибивает.
источник
Integer.MAX_VALUE
. Контраст с-(-Integer.MIN_VALUE) != Integer.MIN_VALUE
.-Integer.MIN_VALUE
оборачиваетсяInteger.MIN_VALUE
, так отрицая, что снова просто производитInteger.MIN_VALUE
снова.-x = (~x) + 1
.Ответы:
На Java это ничего не значит.
Но этот комментарий говорит, что эта строка специально для GWT, который является способом компиляции Java в JavaScript.
В JavaScript целые числа вроде как удваивают то, что действуют как целые числа. Например, они имеют максимальное значение 2 ^ 53. Но побитовые операторы обрабатывают числа, как если бы они были 32-битными, а это именно то, что вам нужно в этом коде. Другими словами, в JavaScript
~~hash
написано «рассматриватьhash
как 32-разрядное число». В частности, он отбрасывает все, кроме младших 32 бит (так как побитовое~
операторы смотрят только на нижние 32 бита), что идентично тому, как работает переполнение Java.Если у вас его нет, хеш-код объекта будет отличаться в зависимости от того, будет ли он оценен на Java-земле или на JavaScript-земле (посредством компиляции GWT).
источник
|0
или~~
звучит так, как будто это не сложно, хотя я не знаю, каким будет удар по производительности (его нужно добавлять на каждом шаге каждого выражения). Я не знаю, каковы были соображения дизайна. Между прочим, несоответствие задокументировано на странице совместимости GWT .hashCode
странно, что он намеренно вызывает или даже ожидает, что произойдет переполнение. Единственное место, где вы можете наблюдать несогласованность, - это переполнение нормального Java int, что не является проблемой, встречающейся в большинстве кода; это просто актуально в этом странном случае.