2015-04-19 6 views
186

Wenn Sie den Quellcode von Guava Surfen, stieß ich auf das folgende Stück Code (Teil der Umsetzung von hashCode für die innere Klasse CartesianSet):Was bedeutet doppelte Tilde (~~) in 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; 

Beide adjust und hash sind int s. Von dem, was ich über Java weiß, bedeutet ~ bitweises Negieren, also sollten adjust = ~~adjust und die Variablen unverändert lassen. Das Ausführen des kleinen Tests (mit natürlich aktivierten Zusicherungen),

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

bestätigt dies. Unter der Annahme, dass die Guava-Jungs wissen, was sie tun, muss es einen Grund für sie geben, dies zu tun. Die Frage ist was?

EDIT Wie in den Kommentaren darauf hingewiesen, wird der Test über den Fall nicht enthalten, in dem iInteger.MAX_VALUE entspricht. Da i <= Integer.MAX_VALUE immer wahr ist, müssen wir diesen Fall außerhalb der Schleife überprüfen, um zu verhindern, dass er für immer durchläuft. Die Zeile

ergibt jedoch die Compiler-Warnung "Vergleichen identischer Ausdrücke", die es ziemlich nagt.

+41

@dr_andonuts Guava ist eine hübsche Standard-Bibliothek, die heutzutage in ein Projekt aufgenommen wird - ich denke, der Rat, weit weg zu rennen, ist fehl am Platz. – yshavit

+4

Die Assert prüft nicht den Kantenfall 'Integer.MAX_VALUE'. Kontrast mit '- (- Integer.MIN_VALUE)! = Integer.MIN_VALUE'. – Franky

+1

@Franky Sie haben Recht mit dem fehlenden Testfall, aber falsch mit dem anderen Teil wie für jeden 'int', beide' - (- x) 'und' ~ (~ x) 'gleich' x', egal was . – maaartinus

Antwort

237

In Java bedeutet es nichts.

Aber dieser Kommentar sagt, dass die Zeile speziell für GWT ist, was eine Möglichkeit ist, Java in JavaScript zu kompilieren.

In JavaScript sind Ganzzahlen wie Doppelgänger, die als Ganzzahlen fungieren. Sie haben zum Beispiel einen maximalen Wert von 2^53. Aber bitwise operators behandeln Zahlen, als ob sie 32-Bit sind, was genau das ist, was Sie in diesem Code wollen. Mit anderen Worten, ~~hash sagt "Behandle hash als 32-Bit-Nummer" in JavaScript. Insbesondere verwirft er alle außer den unteren 32 Bits (da die bitweisen ~ Operatoren nur die unteren 32 Bits betrachten), was identisch ist mit dem Überlauf von Java.

Wenn Sie das nicht hatten, würde der Hash-Code des Objekts davon abhängen, ob es in Java-Land oder in JavaScript Land ausgewertet wird (über eine GWT-Kompilierung).

+2

Das macht Sinn. Es scheint auch so, als würde der JIT-Compiler die Anweisungen optimieren: Wenn ich den obigen "Test" ausgeführt habe, ist er so schnell beendet worden, dass es aussieht, als ob die gesamte Schleife als toter Code entfernt würde. –

+0

Also GWT ist kaputt und implementiert Integer standardmäßig falsch? Das ist ... irgendwie gruselig – harold

+10

@harold Es ist keine GWT-Sache, es ist eine JavaScript-Sache. Das ist gerade jetzt Zahlen arbeiten in dieser Sprache. – yshavit