Beim Durchsuchen des Quellcodes von Guava stieß ich auf den folgenden Code (Teil der Implementierung von hashCode
für die innere Klasse 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;
Beide von adjust
und hash
sind int
s. Soweit ich über Java weiß, ~
bedeutet dies bitweise Negation adjust = ~~adjust
und hash = ~~hash
sollte die Variablen unverändert lassen. Ausführen des kleinen Tests (mit aktivierten Zusicherungen natürlich),
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
assert i == ~~i;
}
bestätigt dies. Vorausgesetzt, die Guaven wissen, was sie tun, muss es einen Grund für sie geben, dies zu tun. Die Frage ist was?
BEARBEITEN Wie in den Kommentaren ausgeführt, enthält der obige Test nicht den Fall, in dem i
gleich ist Integer.MAX_VALUE
. Da dies i <= Integer.MAX_VALUE
immer der Fall ist, müssen wir diesen Fall außerhalb der Schleife überprüfen, um zu verhindern, dass er für immer wiederholt wird. Allerdings ist die Linie
assert Integer.MAX_VALUE == ~~Integer.MAX_VALUE;
gibt die Compiler-Warnung "Vergleichen identischer Ausdrücke" aus, die es so ziemlich nagelt.
quelle
Integer.MAX_VALUE
. Kontrast zu-(-Integer.MIN_VALUE) != Integer.MIN_VALUE
.-Integer.MIN_VALUE
wickelt sich umInteger.MIN_VALUE
, so negiert das wieder einfachInteger.MIN_VALUE
wieder.-x = (~x) + 1
.Antworten:
In Java bedeutet es nichts.
Dieser Kommentar besagt jedoch, dass die Zeile speziell für GWT bestimmt ist. Dies ist eine Möglichkeit, Java zu JavaScript zu kompilieren.
In JavaScript sind Ganzzahlen wie Doppelzahlen, die als Ganzzahlen fungieren. Sie haben zum Beispiel einen Maximalwert von 2 ^ 53. Aber Bitoperatoren behandelt Zahlen , als ob sie 32-Bit sind, das ist genau das , was Sie in diesem Code werden sollen. Mit anderen Worten,
~~hash
sagt "hash
Als 32-Bit-Zahl behandeln" in JavaScript. Insbesondere werden alle bis auf die unteren 32 Bits verworfen (da die bitweisen~
Operatoren nur die unteren 32 Bits betrachten), was mit der Funktionsweise des Java-Überlaufs identisch ist.Wenn Sie das nicht hätten, wäre der Hash-Code des Objekts unterschiedlich, je nachdem, ob es in Java-Land oder in JavaScript-Land (über eine GWT-Kompilierung) ausgewertet wird.
quelle
|0
oder~~
klingt so, als wäre es nicht schwer, obwohl ich nicht weiß, wie der Performance-Hit aussehen würde (Sie müssten es bei jedem Schritt jedes Ausdrucks hinzufügen). Ich weiß nicht, was die Designüberlegungen waren. Fwiw, die Inkonsistenz ist auf der GWT-Kompatibilitätsseite dokumentiert .hashCode
ist insofern seltsam, als es absichtlich einen Überlauf umwirbt oder sogar erwartet. Der einzige Ort, an dem Sie Inkonsistenzen beobachten können, ist der Ort, an dem ein normaler Java-Int überlaufen würde. Dies ist kein Problem, das im meisten Code auftritt. es ist nur in diesem einen seltsamen Fall relevant.