2015-04-19 4 views
186

При просмотре исходного кода гуавы, я наткнулся на следующий фрагмент кода (часть реализации hashCode для внутреннего класса CartesianSet):В чем смысл двойной тильды (~~) в Java?

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; 
} 

подтверждает это. Предполагая, что ребята из Guava знают, что они делают, для этого должна быть причина. Вопрос в том, что?

EDIT Как было отмечено в комментариях выше тест не включает в себя случай, когда i приравнивает Integer.MAX_VALUE. Поскольку i <= Integer.MAX_VALUE всегда истинно, нам нужно будет проверить этот случай вне цикла, чтобы он не зацикливался навсегда. Однако линия

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

дает предупреждение о компиляторе «Сравнение идентичных выражений», что в значительной степени прибивает его.

+41

@dr_andonuts Guava - довольно стандартная библиотека для включения в проект в наши дни - я думаю, что совет, чтобы бежать далеко, неуместен. – yshavit

+4

Утверждение не проверяет кромку края 'Integer.MAX_VALUE'. Контраст с '- (- Integer.MIN_VALUE)! = Integer.MIN_VALUE'. – Franky

+1

@Franky. Вы правы с отсутствующим тестовым примером, но неправильно с другой частью, как и для каждого 'int', как' - (- x) ', так и' ~ (~ x) 'equal' x', независимо от того, что , – maaartinus

ответ

237

В Java это ничего не значит.

Но в этом комментарии говорится, что строка специально предназначена для GWT, что является способом компиляции Java на JavaScript.

В JavaScript целые числа являются похожими на doubles-the-act-as-integers. Например, они имеют максимальное значение 2^53. Но bitwise operators обрабатывают номера так, как будто они 32-разрядные, что именно то, что вы хотите в этом коде. Другими словами, ~~hash говорит «обрабатывать hash как 32-разрядное число» в JavaScript. В частности, он отбрасывает все, кроме нижних 32 бита (поскольку побитовые операторы ~ смотрят только на нижние 32 бита), что идентично тому, как работает переполнение Java.

Если у вас этого нет, хеш-код объекта будет отличаться в зависимости от того, будет ли он оценен в Java-land или на земле JavaScript (с помощью компиляции GWT).

+2

Это имеет смысл. Также кажется, что компилятор JIT оптимизирует утверждения: когда я запускал «тест» выше, он вышел так быстро, что кажется, что весь цикл удаляется как мертвый код. –

+0

Итак, GWT сломан, и по умолчанию реализует целые числа неправильно? Это .. вроде страшно – harold

+10

@harold Это не вещь GWT, это вещь для JavaScript. Вот только цифры работают на этом языке. – yshavit

Смежные вопросы