Przeglądając kod źródłowy Guava natrafiłem na następujący fragment kodu (część implementacji hashCode
klasy wewnętrznej 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;
Oba są adjust
i hash
są int
. Z tego, co wiem o Javie, ~
oznacza bitową negację, więc adjust = ~~adjust
i hash = ~~hash
powinienem pozostawić zmienne bez zmian. Uruchomienie małego testu (oczywiście z włączonymi asercjami),
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
assert i == ~~i;
}
potwierdza to. Zakładając, że Guava wiedzą, co robią, musi istnieć powód, aby to zrobić. Pytanie brzmi: co?
EDYCJA Jak wskazano w komentarzach, powyższy test nie obejmuje przypadku, w którym i
jest równy Integer.MAX_VALUE
. Ponieważ i <= Integer.MAX_VALUE
zawsze jest to prawdą, musimy sprawdzić tę skrzynkę poza pętlą, aby zapobiec jej zapętleniu na zawsze. Jednak linia
assert Integer.MAX_VALUE == ~~Integer.MAX_VALUE;
wyświetla ostrzeżenie kompilatora „Porównywanie identycznych wyrażeń”, które w znacznym stopniu go dotyka.
Integer.MAX_VALUE
. Porównaj z -(-Integer.MIN_VALUE) != Integer.MIN_VALUE
.
-Integer.MIN_VALUE
owija się wokół Integer.MIN_VALUE
, tak negując, że znów po prostu produkuje Integer.MIN_VALUE
ponownie.
-x = (~x) + 1
.