web-dev-qa-db-fra.com

Pourquoi les comparaisons == avec Integer.valueOf (String) donnent-elles des résultats différents pour 127 et 128?

Je ne sais pas pourquoi ces lignes de code renvoient des valeurs différentes:

System.out.println(Integer.valueOf("127")==Integer.valueOf("127"));
System.out.println(Integer.valueOf("128")==Integer.valueOf("128"));
System.out.println(Integer.parseInt("128")==Integer.valueOf("128"));

La sortie est:

true
false
true

Pourquoi le premier retourne-t-il true et le second false? Y at-il quelque chose de différent que je ne connais pas entre 127 et 128? (Bien sûr, je sais que 127 <128.)

Aussi, pourquoi le troisième retourne-t-il true?

J'ai lu la réponse de cette question , mais je n'ai toujours pas compris comment il peut renvoyer true et pourquoi le code de la deuxième ligne renvoie false.

177
DnR

Il y a une différence frappante ici.

valueOf renvoie un objet Integer dont les valeurs peuvent être mises en cache entre -128 et 127. C’est pourquoi la première valeur renvoie true - il est mis en cache - et la deuxième valeur renvoie false - 128 n'est pas une valeur mise en cache, vous obtenez donc deux instances distinctes Integer.

Il est important de noter que vous comparez les références avec Integer#valueOf, Et si vous comparez une valeur plus grande que celle du cache. pas sera évalué à true, même si les valeurs analysées sont équivalentes (exemple: Integer.valueOf(128) == Integer.valueOf(128)). Vous must utilisez equals() à la place.

parseInt renvoie une primitive int. C'est pourquoi la troisième valeur renvoie true - 128 == 128 Est évaluée et bien sûr, true.

Maintenant, un peu juste arrive à faire ce troisième résultat true:

  • ne conversion unboxing a lie en ce qui concerne l'opérateur d'équivalence que vous utilisez et les types de données que vous avez - à savoir, int et Integer. Vous obtenez bien sûr un Integer de valueOf à droite.

  • Après la conversion, vous comparez deux valeurs primitives int. La comparaison se déroule exactement comme vous le souhaiteriez pour les primitives. Vous devez donc comparer 128 Et 128.

189
Makoto

La classe Integer a un cache statique qui stocke 256 objets spéciaux Integer - un pour chaque valeur comprise entre -128 et 127. Considérez la différence entre ces trois éléments.

new Integer(123);

Ceci (évidemment) crée un nouvel objet Integer.

Integer.parseInt("123");

Ceci retourne une valeur primitive int après l'analyse de String.

Integer.valueOf("123");

C'est plus complexe que les autres. Il commence par analyser le String. Ensuite, si la valeur est comprise entre -128 et 127, l'objet correspondant est renvoyé du cache statique. Si la valeur est en dehors de cette plage, il appelle alors new Integer() et transmet la valeur, de sorte que vous obteniez un nouvel objet.

Maintenant, considérons les trois expressions de la question.

Integer.valueOf("127")==Integer.valueOf("127");

Cela renvoie true, car le Integer dont la valeur est 127 est extrait deux fois du cache statique et comparé à lui-même. Un seul objet Integer est impliqué, ce qui retourne donc true.

Integer.valueOf("128")==Integer.valueOf("128");

Ceci retourne false, car 128 n'est pas dans le cache statique. Donc, un nouveau Integer est créé pour chaque côté de l'égalité. Puisqu'il y a deux objets Integer différents et que == Pour les objets ne renvoie que true si les deux côtés sont exactement le même objet, il s'agira de false .

Integer.parseInt("128")==Integer.valueOf("128");

Ceci compare la primitive int valeur 128 à gauche avec un nouvel objet Integer créé à droite. Mais comme il n’a pas de sens de comparer un int à un Integer, Java décochera automatiquement le Integer avant de le vous comparez donc un int à un int. Puisque la primitive 128 est égale à elle-même, elle renvoie true.

122
Dawood ibn Kareem

Prenez soin de renvoyer les valeurs de ces méthodes. La méthode valueOf renvoie l'instance Integer:

public static Integer valueOf(int i)

La méthode parseInt renvoie une valeur entière (type primitif):

public static int parseInt(String s) throws NumberFormatException

Explication pour la comparaison:

Afin d'économiser de la mémoire, deux instances des objets wrapper seront toujours == lorsque leurs valeurs primitives sont les mêmes:

  • Booléen
  • Octet
  • Caractère de\u0000 à\u007f (7f est 127 en décimal)
  • Short et Integer de -128 à 127

Lorsque == est utilisé pour comparer une primitive à un wrapper, celui-ci sera décompressé et la comparaison sera primitive à primitive.

Dans votre situation (selon les règles ci-dessus):

Integer.valueOf("127")==Integer.valueOf("127")

Cette expression compare les références au même objet, car il contient une valeur entière comprise entre -128 et 127, de sorte qu'il renvoie la valeur true.

Integer.valueOf("128")==Integer.valueOf("128")

Cette expression compare les références à différents objets car ils contiennent des valeurs entières non comprises dans <-128, 127>, de sorte qu'elle renvoie la valeur false.

Integer.parseInt("128")==Integer.valueOf("128")

Cette expression compare la valeur primitive (côté gauche) et la référence à l'objet (côté droit) afin que le côté droit soit déballé et que son type primitif soit comparé à celui de gauche, de sorte qu'il renvoie la valeur true.

13
piobab

Les objets Integer mettent en cache entre -128 et 127 sur 256 Integer

Vous ne devez pas comparer les références d'objet avec == ou ! =. Vous devriez utiliser .equals (..) à la place, ou mieux - utilisez la primitive int plutôt que Integer.

parseInt: Analyse l'argument de chaîne en tant qu'entier décimal signé. Les caractères de la chaîne doivent tous être des chiffres décimaux, sauf que le premier caractère peut être un ASCII signe moins - '\ u002D')) pour indiquer une valeur négative. La valeur entière résultante est retourné, exactement comme si l'argument et la base 10 étaient donnés en arguments à la méthode parseInt (Java.lang.String, int).

--- (valueOf Retourne un objet Integer contenant la valeur extraite de la chaîne spécifiée lors de l'analyse avec la base donnée par le second argument. Le premier argument est interprété comme représentant un entier signé dans la base spécifiée par le second argument, exactement comme si les arguments étaient donnés à la méthode parseInt (Java.lang.String, int). Le résultat est un objet Integer qui représente la valeur entière spécifiée par la chaîne.

équivalent à

new Integer(Integer.parseInt(s, radix))

radix - la radix à utiliser pour interpréter s

donc, si vous égalez Integer.valueOf() pour l'entier intermédiaire

-128 à 127 il retourne vrai dans votre condition

pour lesser than -128 et greater than 127, cela donne false

6
Nambi

Pour compléter les réponses données, prenez également note des éléments suivants:

public class Test { 
    public static void main(String... args) { 
        Integer a = new Integer(129);
        Integer b = new Integer(129);
        System.out.println(a == b);
    }
}

Ce code affichera également: false

Comme l'utilisateur Jay a déclaré dans un commentaire pour la réponse acceptée, il faut faire attention lors de l'utilisation de l'opérateur == sur les objets, vous vérifiez ici si les deux références sont identiques, ce qui n’est pas le cas, car il s’agit d’objets différents, bien qu’ils représentent exactement la même valeur. Pour comparer des objets, utilisez plutôt la méthode equals:

Integer a = new Integer(128);
Integer b = new Integer(128);
System.out.println(a.equals(b));

Cela affichera: true

Vous pouvez demander, Mais alors pourquoi la première ligne imprimée true? . Vérification du code source pour le Integer.valueOf _ méthode, vous pouvez voir ce qui suit:

public static Integer valueOf(String s) throws NumberFormatException {
    return Integer.valueOf(parseInt(s, 10));
}

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

Si le param est un entier compris entre IntegerCache.low (par défaut à -128) et IntegerCache.high (calculé à l'exécution avec une valeur minimale de 127), un objet pré-alloué (mis en cache) est renvoyé. Ainsi, lorsque vous utilisez 127 en tant que paramètre, vous obtenez deux références au même objet mis en cache et vous obtenez true dans la comparaison des références.

6
higuaro