Was bedeutet die doppelte Tilde (~~) in Java?

Lesezeit: 3 Minuten

Benutzer-Avatar
bisgardo

Beim Durchsuchen des Quellcodes von Guava bin ich auf das folgende Stück Code gestoßen (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 ints. Soweit ich über Java weiß, ~ bedeutet bitweise Negation, also adjust = ~~adjust und hash = ~~hash sollte die Variablen unverändert lassen. Ausführen des kleinen Tests (natürlich mit aktivierten Behauptungen),

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

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

BEARBEITEN Wie in den Kommentaren erwähnt, enthält der obige Test nicht den Fall, in dem i gleich Integer.MAX_VALUE. Seit i <= Integer.MAX_VALUE immer wahr ist, müssen wir diesen Fall außerhalb der Schleife überprüfen, um zu verhindern, dass er sich für immer wiederholt. Allerdings die Linie

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

ergibt die Compiler-Warnung “Vergleich identischer Ausdrücke”, die es ziemlich genau trifft.

  • @dr_andonuts Guava ist heutzutage eine ziemliche Standardbibliothek, die man in ein Projekt aufnehmen kann – ich denke, der Rat, weit weg zu laufen, ist fehl am Platz.

    – yshavit

    19. April 2015 um 23:19 Uhr

  • Das Assert prüft den Randfall nicht Integer.MAX_VALUE. Gegensatz zu -(-Integer.MIN_VALUE) != Integer.MIN_VALUE.

    – Franky

    20. April 2015 um 7:04 Uhr

  • @Franky Was maaartinus gesagt hat. -Integer.MIN_VALUE wickelt sich um Integer.MIN_VALUEso dass das erneute Negieren einfach produziert Integer.MIN_VALUE wieder.

    Benutzer743382

    20. April 2015 um 8:24 Uhr

  • @maaartinus, @hvd, danke für den Hinweis. Jetzt erinnere ich mich daran -x = (~x) + 1.

    – Franky

    20. April 2015 um 8:51 Uhr

  • @dr_andonuts Trolling? Warum vor Dingen davonlaufen, die du nicht verstehst. Dafür ist StackOverflow da: um Ihnen beim Lernen zu helfen.

    – Jared Burrows

    20. April 2015 um 14:58 Uhr

In Java bedeutet es nichts.

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

In JavaScript sind Integer so etwas wie Doubles, die als Integer fungieren. Sie haben zum Beispiel einen Maximalwert von 2^53. Aber bitweise Operatoren Behandeln Sie Zahlen so, als wären sie 32-Bit, was genau das ist, was Sie in diesem Code wollen. Mit anderen Worten, ~~hash sagt “behandeln hash als 32-Bit-Zahl” in JavaScript. Insbesondere werden alle außer den unteren 32 Bits verworfen (da die bitweise ~ Operatoren sehen nur die unteren 32 Bit), was identisch ist mit der Funktionsweise von Javas Überlauf.

Wenn Sie das nicht hätten, wäre der Hash-Code des Objekts unterschiedlich, je nachdem, ob es im Java-Land oder im JavaScript-Land (über eine GWT-Kompilierung) ausgewertet wird.

  • @harold Es ist keine GWT-Sache, es ist eine JavaScript-Sache. Das ist nur, dass Zahlen in dieser Sprache funktionieren.

    – yshavit

    20. April 2015 um 12:05 Uhr

  • @yshavit Es ist jedoch so nicht wie Zahlen in Java funktionieren. Wenn GWT dem Benutzer nicht verschweigt, dass Zahlen in JS und auf der JVM unterschiedlich implementiert sind, dann ist es in der Tat ein schlechter Compiler.

    – Waldmann

    20. April 2015 um 12:57 Uhr

  • @harold, ja, es ist JavaScript, das Ganzzahlen falsch implementiert (in JavaScript gibt es eigentlich keinen ganzzahligen Typ).

    – Mike G

    20. April 2015 um 13:07 Uhr

  • @valderman Das ist ein guter Punkt. Hinzufügen der |0 oder ~~ hört sich so an, als wäre es nicht schwer, obwohl ich nicht weiß, wie der Performance-Hit aussehen würde (Sie müssten ihn bei jedem Schritt jedes Ausdrucks hinzufügen). Ich weiß nicht, was die Designüberlegungen waren. Fwiw, die Inkonsistenz ist dokumentiert Kompatibilitätsseite von GWT.

    – yshavit

    20. April 2015 um 13:19 Uhr


  • hashCode ist darin seltsam, dass es absichtlich Gerichte, oder sogar erwartet, dass ein Überlauf passiert. Die einzige Stelle, an der Sie Inkonsistenzen beobachten können, ist dort, wo ein normaler Java-Int überlaufen würde, was in den meisten Codes kein Problem darstellt. es ist nur in diesem einen seltsamen Fall relevant.

    – Louis Wassermann

    20. April 2015 um 18:54 Uhr

1352330cookie-checkWas bedeutet die doppelte Tilde (~~) in Java?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy