Comparaison des valeurs longues encadrées 127 et 128

111

Je veux comparer deux valeurs d'objets Long en utilisant des ifconditions. Lorsque ces valeurs sont inférieures à 128 , la ifcondition fonctionne correctement, mais lorsqu'elles sont supérieures ou égales à 128 , la comparaison échoue.

Exemple:

Long num1 = 127;
Long num2 = 127;

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

La comparaison sur le code ci-dessus fonctionne correctement, mais échoue dans le code ci-dessous:

Long num1 = 128;
Long num2 = 128;

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

Pourquoi y a-t-il un problème à comparer des variables Long avec des valeurs supérieures à 127 ? Si les types de données de variables sont remplacés par de longues primitives , les comparaisons fonctionnent pour tous les cas.

Viraj Dhamal
la source

Réponses:

212

TL; DR

Java met en cache les instances Integer encadrées de -128à 127. Étant donné que vous utilisez ==pour comparer des références d' objets au lieu de valeurs , seuls les objets mis en cache correspondent. Travaillez avec longdes valeurs primitives sans boîte ou utilisez .equals()pour comparer vos Longobjets.

Version longue (jeu de mots)

Pourquoi y a-t-il un problème à comparer une variable longue avec une valeur supérieure à 127? Si le type de données de la variable ci-dessus est primitif (long), le code fonctionne pour toutes les valeurs.

Java met en cache les instances d'objets Integer comprises entre -128 et 127 . Cela dit:

  • Si vous définissez la valeur sur N variables longues 127( mises en cache ), la même instance d'objet sera pointée par toutes les références. (N variables, 1 instance)
  • Si vous définissez la valeur sur N variables longues 128( non mises en cache ), vous aurez une instance d'objet pointée par chaque référence. (N variables, N instances)

C'est pourquoi ceci:

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

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

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

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

Sort ceci:

vrai
faux

Pour la valeur 127L , puisque les deux références (val1 et val2) pointent vers la même instance d'objet en mémoire (mise en cache), elle renvoie true.

D'autre part, pour la valeur 128 , puisqu'il n'y a pas d'instance pour elle en mémoire cache, une nouvelle est créée pour toutes les nouvelles affectations pour les valeurs encadrées, ce qui entraîne deux instances différentes (pointées par val3 et val4) et retournant falsesur le comparaison entre eux.

Cela se produit uniquement parce que vous comparez deux Long références d'objet , et non longdes valeurs primitives, avec l' ==opérateur. Si ce n'était pas pour ce mécanisme de cache, ces comparaisons échoueraient toujours , donc le vrai problème ici est de comparer les valeurs encadrées avec l' ==opérateur.

Changer ces variables en longtypes primitifs évitera que cela se produise, mais au cas où vous auriez besoin de conserver votre code à l'aide d' Longobjets, vous pouvez effectuer ces comparaisons en toute sécurité avec les approches suivantes:

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

(Une vérification correcte des valeurs nulles est nécessaire, même pour les moulages)

IMO , c'est toujours une bonne idée de s'en tenir aux méthodes .equals () lors de la comparaison d'objets.

Liens de référence:

Everton
la source
15

Java met en cache les valeurs primitives de -128 à 127 . Lorsque nous comparons deux objets Long java, tapez en interne le cast en valeur primitive et le comparons. Mais au-dessus de 127, l'objet Long n'obtiendra pas de caste de type. Java met en cache la sortie par la méthode .valueOf () .

Cette mise en cache fonctionne pour Byte, Short, Long de -128 à 127. Pour Integer, la mise en cache fonctionne De -128 à java.lang.Integer.IntegerCache.high ou 127, selon la valeur la plus élevée. (Nous pouvons définir la valeur de niveau supérieur jusqu'à quelle valeur Integer devrait être mis en cache à l'aide de 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".

Les objets Float et Double ne sont jamais mis en cache.

Le personnage obtiendra le cache de 0 à 127

Vous comparez deux objets. donc l' opérateur == vérifiera l'égalité des références d'objet. Il existe des moyens suivants pour le faire.

1) tapez les deux objets en valeurs primitives et comparez

    (long)val3 == (long)val4

2) lire la valeur de l'objet et comparer

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

3) Utilisez la méthode equals () pour la comparaison d'objets.

    val3.equals(val4);  
Geai
la source
14

num1et num2sont des objets longs. Vous devriez les utiliser equals()pour les comparer. ==La comparaison peut parfois fonctionner à cause de la manière dont la JVM transfère les primitives, mais n'en dépendez pas.

if (num1.equals(num1))
{
 //code
}
Nishan
la source
1
Ceci (ce qui est mieux), ou comparez la valeur de retour de .longValue().
Giulio Franco
4

La comparaison des non-primitifs (aka Objects) en Java avec ==compare leur référence au lieu de leurs valeurs. Longest une classe et donc les Longvaleurs sont des objets.

Le problème est que les développeurs Java voulaient que les gens utilisent Longcomme ils avaient l'habitude longde fournir la compatibilité, ce qui a conduit au concept de l'autoboxing, qui est essentiellement la fonctionnalité, que long-values ​​sera changé en Long-Objects et vice versa si nécessaire. Le comportement de la boxe automatique n'est pas exactement prévisible à tout moment, car il n'est pas complètement spécifié.

Donc, pour être en sécurité et pour avoir des résultats prévisibles, utilisez toujours .equals()pour comparer des objets et ne comptez pas sur l'autoboxing dans ce cas:

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