Ao navegar no código fonte do Guava, me deparei com o seguinte trecho de código (parte da implementação de hashCode
para a 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;
Ambos adjust
e hash
são int
s. Pelo que sei sobre Java, ~
significa negação bit a bit, portanto, adjust = ~~adjust
e hash = ~~hash
deve deixar as variáveis inalteradas. Executando o pequeno teste (com afirmações ativadas, é claro),
for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) {
assert i == ~~i;
}
confirma isso. Supondo que os caras da Goiaba saibam o que estão fazendo, deve haver uma razão para eles fazerem isso. A questão é o que?
EDITAR Como apontado nos comentários, o teste acima não inclui o caso em que i
é igual Integer.MAX_VALUE
. Como i <= Integer.MAX_VALUE
sempre é verdade, precisaremos verificar esse caso fora do loop para impedir que ele faça loop para sempre. No entanto, a linha
assert Integer.MAX_VALUE == ~~Integer.MAX_VALUE;
gera o aviso do compilador "Comparando expressões idênticas", que praticamente o define.
fonte
Integer.MAX_VALUE
. Contraste com-(-Integer.MIN_VALUE) != Integer.MIN_VALUE
.-Integer.MIN_VALUE
envolveInteger.MIN_VALUE
, negando que novamente simplesmente produzInteger.MIN_VALUE
novamente.-x = (~x) + 1
.Respostas:
Em Java, isso não significa nada.
Mas esse comentário diz que a linha é especificamente para GWT, que é uma maneira de compilar Java para JavaScript.
Em JavaScript, números inteiros são como dobras que atuam como números inteiros. Eles têm um valor máximo de 2 ^ 53, por exemplo. Mas os operadores bit a bit tratam os números como se fossem 32 bits, exatamente o que você deseja neste código. Em outras palavras,
~~hash
diz "tratarhash
como um número de 32 bits" em JavaScript. Especificamente, ele descarta todos, exceto os 32 bits inferiores (já que os~
operadores bit a bit olham apenas para os 32 bits inferiores), o que é idêntico ao funcionamento do estouro de Java.Se você não tivesse isso, o código de hash do objeto seria diferente, dependendo de ser avaliado em Java-land ou JavaScript (por meio de uma compilação GWT).
fonte
|0
ou~~
parece que não seria difícil, embora eu não saiba qual seria o desempenho (você teria que adicioná-lo a cada passo de cada expressão). Não sei quais eram as considerações de design. Fwiw, a inconsistência está documentada na página de compatibilidade do GWT .hashCode
é estranho, pois deliberadamente corteja, ou até espera, um transbordamento. O único lugar em que você pode observar inconsistência é onde um Java int normal seria excedido, o que não é um problema que aparece na maioria dos códigos; é apenas relevante neste caso estranho.