Al examinar el código fuente de Guava, me encontré con el siguiente código (parte de la implementación de hashCode
la clase 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;
Ambos adjust
y hash
son int
s. Por lo que sé acerca de Java, ~
mediante la negación bit a bit, por lo que adjust = ~~adjust
, y hash = ~~hash
debería salir de las variables sin cambios. Ejecutando la pequeña prueba (con aserciones habilitadas, por supuesto),
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
assert i == ~~i;
}
confirma esto Suponiendo que los chicos de la guayaba saben lo que están haciendo, debe haber una razón para que lo hagan. La pregunta es qué?
EDITAR Como se señaló en los comentarios, la prueba anterior no incluye el caso donde i
es igual Integer.MAX_VALUE
. Como i <= Integer.MAX_VALUE
siempre es cierto, tendremos que verificar ese caso fuera del bucle para evitar que se repita para siempre. Sin embargo, la linea
assert Integer.MAX_VALUE == ~~Integer.MAX_VALUE;
produce la advertencia del compilador "Comparación de expresiones idénticas", que prácticamente lo clava.
fuente
Integer.MAX_VALUE
. Contraste con-(-Integer.MIN_VALUE) != Integer.MIN_VALUE
.-Integer.MIN_VALUE
se envuelveInteger.MIN_VALUE
, negando eso nuevamente, simplemente produceInteger.MIN_VALUE
nuevamente.-x = (~x) + 1
.Respuestas:
En Java, no significa nada.
Pero ese comentario dice que la línea es específicamente para GWT, que es una forma de compilar Java a JavaScript.
En JavaScript, los enteros son como dobles-que-actúan como enteros. Tienen un valor máximo de 2 ^ 53, por ejemplo. Pero los operadores bit a bit tratan los números como si fueran de 32 bits, que es exactamente lo que quieres en este código. En otras palabras,
~~hash
dice "tratarhash
como un número de 32 bits" en JavaScript. Específicamente, descarta todos menos los 32 bits inferiores (dado que los~
operadores bit a bit solo miran los 32 bits inferiores), que es idéntico a cómo funciona el desbordamiento de Java.Si no tuviera eso, el código hash del objeto sería diferente dependiendo de si se evalúa en Java-Land o en JavaScript Land (a través de una compilación GWT).
fuente
|0
o~~
suena como si no fuera difícil, aunque no sé cuál sería el éxito en el rendimiento (tendría que agregarlo en cada paso de cada expresión). No sé cuáles fueron las consideraciones de diseño. Fwiw, la inconsistencia está documentada en la página de compatibilidad de GWT .hashCode
es extraño porque deliberadamente corteja, o incluso espera, que ocurra un desbordamiento. El único lugar donde puede observar inconsistencias es donde se desbordaría un int Java normal, que no es un problema que aparece en la mayoría del código; es relevante en este caso extraño.