Qual è il significato di double tilde (~~) in Java?


192

Durante la navigazione del codice sorgente di Guava, mi sono imbattuto nel seguente pezzo di codice (parte dell'implementazione di hashCodeper la classe interna 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;

Entrambi adjuste hashsono ints. Da quello che so di Java, ~significa negazione bit per bit, quindi adjust = ~~adjuste hash = ~~hashdovrebbe lasciare invariate le variabili. Esecuzione del piccolo test (con asserzioni abilitate, ovviamente),

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

lo conferma. Supponendo che i ragazzi di Guava sappiano cosa stanno facendo, ci deve essere un motivo per farlo. La domanda è cosa?

MODIFICA Come sottolineato nei commenti, il test sopra riportato non include il caso in cui è iuguale Integer.MAX_VALUE. Dato che i <= Integer.MAX_VALUEè sempre vero, dovremo controllare quel caso al di fuori del ciclo per impedirne il ciclo per sempre. Tuttavia, la linea

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

produce l'avvertimento del compilatore "Confronto di espressioni identiche", che praticamente lo inchioda.


42
@dr_andonuts Guava è una libreria piuttosto standard da includere in un progetto in questi giorni - penso che il consiglio di scappare lontano sia fuori luogo.
yshavit,

4
L'asserzione non controlla il caso limite Integer.MAX_VALUE. In contrasto con -(-Integer.MIN_VALUE) != Integer.MIN_VALUE.
Franky,

3
@Franky Cosa ha detto Maaartinus. -Integer.MIN_VALUEsi avvolge a Integer.MIN_VALUE, così negando che di nuovo semplicemente produce di Integer.MIN_VALUEnuovo.

2
@maaartinus, @hvd, grazie per averlo segnalato. Ora me lo ricordo -x = (~x) + 1.
Franky,

7
@dr_andonuts Trolling? Perché scappare da cose che non capisci. Questo è lo scopo di StackOverflow: aiutarti a imparare.
Jared Burrows,

Risposte:


245

In Java, non significa nulla.

Ma quel commento dice che la linea è specificamente per GWT, che è un modo per compilare Java in JavaScript.

In JavaScript, i numeri interi sono un po 'come i doppi che agiscono come numeri interi. Hanno un valore massimo di 2 ^ 53, ad esempio. Ma gli operatori bit a bit trattano i numeri come se fossero a 32 bit, che è esattamente quello che vuoi in questo codice. In altre parole, ~~hashdice "tratta hashcome un numero a 32 bit" in JavaScript. In particolare, scarta tutti tranne i 32 bit inferiori (poiché gli ~operatori bit a bit guardano solo i 32 bit inferiori), il che è identico a come funziona l'overflow di Java.

Se non lo avessi, il codice hash dell'oggetto sarebbe diverso a seconda che fosse valutato in Java-land o JavaScript-land (tramite una compilation GWT).


10
@harold Non è una cosa GWT, è una cosa JavaScript. Questo è solo ora i numeri funzionano in quella lingua.
yshavit,

18
@yshavit Tuttavia, è non è come i numeri funzionano in Java. Se GWT non nasconde all'utente il fatto che i numeri siano implementati in modo diverso in JS e in JVM dall'utente, allora è davvero un compilatore scadente.
valderman,

8
@harold, sì, è JavaScript che implementa gli interi in modo errato (in realtà non esiste un tipo intero in JavaScript).
MikeTheLiar,

8
@valderman Questo è un buon punto. L'aggiunta di |0o ~~suona come non sarebbe difficile, anche se non so quale sarebbe il colpo di prestazione (dovresti aggiungerlo ad ogni passo di ogni espressione). Non so quali fossero le considerazioni sul design. In seguito, l'incoerenza è documentata nella pagina di compatibilità di GWT .
yshavit,

6
hashCodeè strano in quanto giudica deliberatamente , o addirittura si aspetta, che accada un trabocco. L'unico posto in cui è possibile osservare l'incoerenza è dove traboccerebbe un normale int Java, che non è un problema che si presenta nella maggior parte del codice; è rilevante solo in questo strano caso.
Louis Wasserman,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.