Comparación de valores largos 127 y 128 en caja

110

Quiero comparar dos valores de objetos largos usando ifcondiciones. Cuando estos valores son menores que 128 , la ifcondición funciona correctamente, pero cuando son mayores o iguales que 128 , la comparación falla.

Ejemplo:

Long num1 = 127;
Long num2 = 127;

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

La comparación en el código anterior funciona correctamente, pero falla en el código siguiente:

Long num1 = 128;
Long num2 = 128;

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

¿Por qué hay un problema al comparar variables Long con valores superiores a 127 ? Si los tipos de datos de las variables se cambian a primitivas largas , las comparaciones funcionan para todos los casos.

Viraj Dhamal
fuente

Respuestas:

212

TL; DR

Java almacena en caché instancias enteras en caja desde -128hasta 127. Dado que está utilizando ==para comparar referencias de objetos en lugar de valores , solo los objetos almacenados en caché coincidirán. longTrabaje con valores primitivos sin caja o utilícelos .equals()para comparar sus Longobjetos.

Versión larga (juego de palabras)

¿Por qué hay un problema al comparar la variable Long con un valor mayor que 127? Si el tipo de datos de la variable anterior es primitivo (largo), el código funciona para todos los valores.

Java almacena en caché instancias de objetos Integer del rango -128 a 127 . Dicho eso:

  • Si establece en N variables largas el valor 127(en caché ), todas las referencias señalarán la misma instancia de objeto. (N variables, 1 instancia)
  • Si establece en N variables largas el valor 128( no almacenado en caché ), tendrá una instancia de objeto apuntada por cada referencia. (N variables, N instancias)

Por eso es que esto:

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

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

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

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

Produce esto:

verdadero
falso

Para el valor 127L , dado que ambas referencias (val1 y val2) apuntan a la misma instancia de objeto en la memoria (en caché), devuelve true.

Por otro lado, para el valor 128 , dado que no hay una instancia almacenada en caché en la memoria, se crea una nueva para cualquier asignación nueva de valores en caja, lo que da como resultado dos instancias diferentes (señaladas por val3 y val4) y regresando falseen el comparación entre ellos.

Eso sucede únicamente porque está comparando dos Long referencias de objeto , no longvalores primitivos, con el ==operador. Si no fuera por este mecanismo de caché, estas comparaciones siempre fallarían, por lo que el verdadero problema aquí es comparar los valores en caja con el ==operador.

Cambiar estas variables a longtipos primitivos evitará que esto suceda, pero en caso de que necesite mantener su código usando Longobjetos, puede hacer estas comparaciones de manera segura con los siguientes enfoques:

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

(Es necesaria una verificación nula adecuada, incluso para fundiciones)

En mi opinión , siempre es una buena idea seguir con los métodos .equals () cuando se trata de comparaciones de objetos.

Enlaces de referencia:

everton
fuente
15

Java almacena en caché los valores primitivos de -128 a 127 . Cuando comparamos dos objetos Long , java internamente escribe, envíalo a un valor primitivo y lo comparamos. Pero por encima de 127, el objeto Long no obtendrá el tipo de casta. Java almacena en caché la salida mediante el método .valueOf () .

Este almacenamiento en caché funciona para Byte, Short, Long de -128 a 127. Para el almacenamiento en caché de Integer funciona de -128 a java.lang.Integer.IntegerCache.high o 127, el que sea mayor. (Podemos establecer el valor de nivel superior hasta qué valores de Integer debería almacenarse en caché 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".

Los objetos Float y Double nunca se almacenan en caché.

El personaje obtendrá caché de 0 a 127

Estás comparando dos objetos. por lo que el operador == verificará la igualdad de referencias a objetos. Hay las siguientes formas de hacerlo.

1) escriba convertir ambos objetos en valores primitivos y comparar

    (long)val3 == (long)val4

2) leer el valor del objeto y comparar

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

3) Utilice el método equals () en la comparación de objetos.

    val3.equals(val4);  
Arrendajo
fuente
14

num1y num2son objetos largos. Deberías estar usando equals()para compararlos. ==la comparación puede funcionar a veces debido a la forma en que las cajas JVM son primitivas, pero no depende de ello.

if (num1.equals(num1))
{
 //code
}
Nishan
fuente
1
Esto (que es mejor), o compare el valor de retorno de .longValue().
Giulio Franco
4

La comparación de no primitivos (también conocidos como Objetos) en Java con ==compara su referencia en lugar de sus valores. Longes una clase y, por tanto, los Longvalores son Objetos.

El problema es que los desarrolladores de Java querían que las personas usaran Longcomo solían longproporcionar compatibilidad, lo que llevó al concepto de autoboxing, que es esencialmente la característica, que long-values ​​se cambiará a Long-Objects y viceversa según sea necesario. Sin embargo, el comportamiento del autoboxing no es exactamente predecible todo el tiempo, ya que no está completamente especificado.

Entonces, para estar seguro y tener resultados predecibles, use siempre .equals()para comparar objetos y no confíe en el autoboxing en este caso:

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