Comparando valores longos em caixas 127 e 128

111

Quero comparar dois valores de objetos longos usando ifcondições. Quando esses valores são menores que 128 , a ifcondição funciona corretamente, mas quando eles são maiores ou iguais a 128 , a comparação falha.

Exemplo:

Long num1 = 127;
Long num2 = 127;

if (num1 == num2) {
    // Works ok
}

A comparação no código acima funciona corretamente, mas falha no código abaixo:

Long num1 = 128;
Long num2 = 128;

if (num1 == num2) {
    // Does NOT work
}

Por que há um problema em comparar variáveis longas com valores maiores que 127 ? Se os tipos de dados das variáveis ​​forem alterados para primitivas longas , as comparações funcionam para todos os casos.

Viraj Dhamal
fonte

Respostas:

212

TL; DR

Java armazena em cache instâncias inteiras em caixa de -128a 127. Como você está usando ==para comparar referências de objetos em vez de valores , apenas os objetos em cache corresponderão. Trabalhe com longvalores primitivos não encaixotados ou use .equals()para comparar seus Longobjetos.

Versão longa (trocadilho intencional)

Por que há problema em comparar a variável longa com valor maior que 127? Se o tipo de dados da variável acima for primitivo (longo), o código funcionará para todos os valores.

Java armazena em cache instâncias de objetos inteiros de -128 a 127 . Dito isto:

  • Se você definir como N variáveis ​​longas o valor 127(em cache ), a mesma instância do objeto será apontada por todas as referências. (N variáveis, 1 instância)
  • Se você definir como N variáveis ​​longas o valor 128( não armazenado em cache ), você terá uma instância de objeto apontada por cada referência. (N variáveis, N instâncias)

É por isso que:

Long val1 = 127L;
Long val2 = 127L;

System.out.println(val1 == val2);

Long val3 = 128L;
Long val4 = 128L;

System.out.println(val3 == val4);

Produz isto:

verdadeiro
falso

Para o valor 127L , como ambas as referências (val1 e val2) apontam para a mesma instância do objeto na memória (em cache), ele retorna true.

Por outro lado, para o valor 128 , uma vez que não há instância para ele em cache na memória, uma nova é criada para quaisquer novas atribuições para valores em caixa, resultando em duas instâncias diferentes (apontadas por val3 e val4) e retornando falseno comparação entre eles.

Isso acontece apenas porque você está comparando duas Long referências de objeto , não longvalores primitivos, com o ==operador. Se não fosse por esse mecanismo de Cache, essas comparações sempre falhariam, então o verdadeiro problema aqui é comparar os valores em caixa com o ==operador.

Alterar essas variáveis ​​para longtipos primitivos impedirá que isso aconteça, mas caso você precise manter seu código usando Longobjetos, pode fazer essas comparações com segurança com as seguintes abordagens:

System.out.println(val3.equals(val4));                     // true
System.out.println(val3.longValue() == val4.longValue());  // true
System.out.println((long)val3 == (long)val4);              // true

(A verificação nula adequada é necessária, mesmo para peças fundidas)

IMO , é sempre uma boa idéia manter os métodos .equals () ao lidar com comparações de objetos.

Links de referência:

Everton
fonte
15

Java armazena em cache os valores primitivos de -128 a 127 . Quando comparamos dois objetos Long java, digite internamente convertê-lo em um valor primitivo e compará-lo. Mas acima de 127, o objeto Longo não obterá a casta do tipo. Java armazena em cache a saída pelo método .valueOf () .

Este armazenamento em cache funciona para Byte, Curto, Longo de -128 a 127. Para o cache de Inteiro funciona de -128 a java.lang.Integer.IntegerCache.high ou 127, o que for maior. (Podemos definir o valor de nível superior até quais valores Inteiros deve ser armazenado em cache usando java.lang.Integer.IntegerCache.high).

 For example:
    If we set java.lang.Integer.IntegerCache.high=500;
    then values from -128 to 500 will get cached and 

    Integer a=498;
    Integer b=499;
    System.out.println(a==b)

    Output will be "true".

Objetos Float e Double nunca são armazenados em cache.

O personagem receberá o cache de 0 a 127

Você está comparando dois objetos. portanto, o operador == verificará a igualdade das referências do objeto. Existem maneiras de fazer isso.

1) digite os dois objetos em valores primitivos e compare

    (long)val3 == (long)val4

2) ler o valor do objeto e comparar

    val3.longValue() == val4.longValue()

3) Use o método equals () na comparação de objetos.

    val3.equals(val4);  
Jay
fonte
14

num1e num2são objetos longos. Você deve usar equals()para compará-los. ==a comparação pode funcionar às vezes por causa da forma como as caixas JVM primitivas, mas não dependa disso.

if (num1.equals(num1))
{
 //code
}
Nishan
fonte
1
Isso (o que é melhor), ou compare o valor de retorno de .longValue().
Giulio Franco
4

Comparar não-primitivos (também conhecidos como objetos) em Java com ==compara sua referência em vez de seus valores. Longé uma classe e, portanto, os Longvalores são Objetos.

O problema é que os desenvolvedores Java queriam que as pessoas usassem Longcomo costumavam longfornecer compatibilidade, o que levou ao conceito de autoboxing, que é essencialmente o recurso, que long-valores serão alterados para Long-Objects e vice-versa conforme necessário. O comportamento do autoboxing não é exatamente previsível o tempo todo, pois não é completamente especificado.

Portanto, para estar seguro e ter resultados previsíveis, use sempre .equals()para comparar objetos e não dependa do autoboxing neste caso:

Long num1 = 127, num2 = 127;
if(num1.equals(num2)) { iWillBeExecutedAlways(); }
LionC
fonte