En parcourant le code source de Guava, je suis tombé sur le morceau de code suivant (faisant partie de l'implémentation de hashCode
pour la classe interne 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;
Les deux adjust
et hash
sont l' int
art. D'après ce que je sais sur Java, ~
signifie négation au niveau du bit, donc adjust = ~~adjust
et hash = ~~hash
devrait laisser les variables inchangées. Lancer le petit test (avec les assertions activées, bien sûr),
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
assert i == ~~i;
}
le confirme. En supposant que les gars de Guava savent ce qu'ils font, il doit y avoir une raison pour eux de le faire. La question est quoi?
EDIT Comme indiqué dans les commentaires, le test ci-dessus n'inclut pas le cas où i
est égal Integer.MAX_VALUE
. Comme i <= Integer.MAX_VALUE
c'est toujours vrai, nous devrons vérifier ce cas en dehors de la boucle pour l'empêcher de boucler pour toujours. Cependant, la ligne
assert Integer.MAX_VALUE == ~~Integer.MAX_VALUE;
renvoie l'avertissement du compilateur "Comparaison d'expressions identiques", ce qui résout le problème.
la source
Integer.MAX_VALUE
. Contraste avec-(-Integer.MIN_VALUE) != Integer.MIN_VALUE
.-Integer.MIN_VALUE
s'enroule autour deInteger.MIN_VALUE
, donc nier que de nouveau produit simplement àInteger.MIN_VALUE
nouveau.-x = (~x) + 1
.Réponses:
En Java, cela ne veut rien dire.
Mais ce commentaire dit que la ligne est spécifiquement pour GWT, qui est un moyen de compiler Java en JavaScript.
En JavaScript, les entiers sont un peu comme des doubles qui agissent comme des entiers. Ils ont une valeur maximale de 2 ^ 53, par exemple. Mais opérateurs au niveau du bit traitent les nombres comme s'ils étaient 32 bits, ce qui est exactement ce que vous voulez dans ce code. En d'autres termes,
~~hash
dit "traiterhash
comme un nombre 32 bits" en JavaScript. Plus précisément, il supprime tous sauf les 32 bits inférieurs (puisque les~
opérateurs au niveau du bit ne regardent que les 32 bits inférieurs), ce qui est identique au fonctionnement du débordement de Java.Si vous ne l'aviez pas, le code de hachage de l'objet serait différent selon qu'il est évalué en Java-land ou en JavaScript land (via une compilation GWT).
la source
|0
ou~~
semble ne pas être difficile, même si je ne sais pas quel serait le succès de la performance (vous devrez l'ajouter à chaque étape de chaque expression). Je ne sais pas quelles étaient les considérations de conception. Fwiw, l'incohérence est documentée sur la page de compatibilité de GWT .hashCode
est étrange dans la mesure où elle courtise délibérément , voire s'attend à ce qu'un débordement se produise. Le seul endroit où vous pouvez observer une incohérence est l'endroit où un int Java normal déborderait, ce qui n'est pas un problème qui se pose dans la plupart du code; c'est juste pertinent dans ce cas étrange.