Question

Je viens du code de scie semblable à ceci:

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a == b);

        Integer c = 100, d = 100;
        System.out.println(c == d);
    }
}

Quand RAN, ce bloc de code affichera:

false
true

Je comprends pourquoi le premier est false: parce que les deux objets sont des objets séparés, de sorte que le == compare les références. Mais je ne peux pas comprendre, pourquoi la deuxième déclaration de retour true? Y at-il une règle de autoboxing étrange qui se déclenche quand une valeur de nombre entier est dans une certaine plage? Qu'est-ce qui se passe ici?

Était-ce utile?

La solution

La ligne true est effectivement garanti par la spécification du langage. De 5.1.7 :

  

Si la valeur p étant boxed est vrai,   faux, un octet, un produit de carbonisation dans la plage   \ U0000 à \ u007f, ou un int ou court   entre -128 et 127, puis laissez   r1 et r2 soient les résultats des deux   conversions boxe de p. C'est toujours   le cas où r1 == r2.

La discussion se poursuit, ce qui suggère que même si votre deuxième ligne de sortie est garantie, la première n'est pas (voir le dernier paragraphe cité ci-dessous):

  

Idéalement, la boxe une primitive donnée   valeur p, serait toujours donner un   référence identique. En pratique, cela,   peut ne pas être réalisable à l'aide existante   techniques de mise en œuvre. Les règles   ci-dessus sont un compromis pragmatique. le   clause finale exige que ci-dessus   certaines valeurs communes sont toujours mis en boîte   en objets impossibles à distinguer. le   la mise en œuvre peut mettre en cache ces derniers, paresseusement   ou avec impatience.

     

Pour d'autres valeurs, cette formulation   toutes les hypothèses sur ne permettant pas la   identité des valeurs sur la boxed   part du programmeur. Cela permettrait   (Mais pas besoin) le partage d'une partie ou   toutes ces références.

     

Cela garantit que, dans le plus courant   des cas, le comportement sera le   une souhaitée, sans imposer une excessive   pénalité de performance, en particulier sur   petits appareils. Moins de mémoire limitée   mises en œuvre pourrait, par exemple,   cache tous les caractères et courts métrages, comme   ainsi que des entiers et désire ardemment dans la   gamme de -32K -. + 32K

Autres conseils

public class Scratch
{
   public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;  //1
        System.out.println(a == b);

        Integer c = 100, d = 100;  //2
        System.out.println(c == d);
   }
}

Sortie:

false
true

Yep la première sortie est produit pour comparer référence; « A » et « b » - ce sont deux références différentes. Au point 1, en fait deux références sont créées qui est similaire -

Integer a = new Integer(1000);
Integer b = new Integer(1000);

La deuxième sortie est produit parce que le JVM essaie d'économiser la mémoire, lorsque le Integer tombe dans une plage (-128 à 127). Au point 2 aucune nouvelle référence de type entier est créé pour « d ». Au lieu de créer un nouvel objet pour la variable de référence de type Entier « d », il n'assigné avec l'objet créé précédemment référencé par « c ». Tous ces éléments sont fait par JVM.

Ces règles d'économie de mémoire ne sont pas seulement pour les entiers. à des fins d'économie de mémoire, deux instances des objets wrapper suivants (tout créé par la boxe), seront toujours == où leurs valeurs primitives sont les mêmes -

  • Boolean
  • Byte
  • Caractère de \ u0000 à \u007f (7f est 127 en décimal)
  • Court et entier de -128 127

Les objets entiers dans une plage (je pense peut-être -128 à 127) se cache et réutilisée. Entiers dehors de cette plage obtenir un nouvel objet à chaque fois.

Oui, il y a une règle étrange autoboxing qui se déclenche lorsque les valeurs sont dans une certaine plage. Lorsque vous attribuez une constante à une variable d'objet, rien dans la définition du langage dit un nouvel objet doit créer. Il peut réutiliser un objet existant à partir du cache.

En fait, la machine virtuelle Java habituellement stocker un cache de petites Entiers à cet effet, ainsi que des valeurs telles que Boolean.TRUE et Boolean.FALSE.

C'est un point intéressant. Dans le livre Effective Java suggère toujours surchargent equals pour vos propres classes. Que, pour vérifier l'égalité pour les deux instances d'objet d'une classe java utilisent toujours la méthode equals.

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a.equals(b));

        Integer c = 100, d = 100;
        System.out.println(c.equals(d));
    }
}

retours:

true
true

Je suppose que Java conserve un cache de petits entiers qui sont déjà « mis en boîte » parce qu'ils sont très fréquents et il enregistre un diable de beaucoup de temps pour la réutilisation d'un objet existant que de créer un nouveau.

En Java les works boxe dans l'intervalle compris entre -128 et 127 pour un nombre entier. Lorsque vous utilisez des numéros dans cette gamme, vous pouvez le comparer avec l'opérateur ==. Pour les objets Entier dehors de la plage, vous devez utiliser égale.

Affectation directe d'un littéral int à une référence entier est un exemple d'auto-boxing, où la valeur littérale au code de conversion d'objet est géré par le compilateur.

Ainsi, pendant les convertis du compilateur de phase de compilation Integer a = 1000, b = 1000; à Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);.

Il est donc méthode Integer.valueOf() qui nous donne en fait les objets entiers, et si l'on regarde le code source de la méthode de Integer.valueOf() nous pouvons voir clairement les objets méthode entiers caches dans la comprise entre -128 et 127 (inclus).

/**
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
 public static Integer valueOf(int i) {
     if (i >= IntegerCache.low && i <= IntegerCache.high)
         return IntegerCache.cache[i + (-IntegerCache.low)];
     return new Integer(i);
 }

Ainsi, au lieu de créer de nouveaux objets et le retour des entiers, Integer.valueOf() la méthode retourne Objets Entier de la IntegerCache interne si le littéral int transmise est supérieure à -128 et inférieur à 127.

Java met en cache ces objets entiers, car cette gamme d'entiers se sert beaucoup dans la journée à la programmation de jour, ce qui permet d'économiser indirectement de la mémoire.

Le cache est initialisé sur la première utilisation lorsque la classe est chargé en mémoire à cause du bloc statique. La portée maximale du cache peut être contrôlé par l'option JVM -XX:AutoBoxCacheMax.

Ce comportement de mise en cache est pas applicable pour des objets entiers seulement, semblable à Integer.IntegerCache nous avons aussi ByteCache, ShortCache, LongCache, CharacterCache pour Byte, Short, Long, Character respectivement.

Vous pouvez en savoir plus sur mon article Java Entier Cache - Pourquoi Integer.valueOf (127) == Integer.valueOf (127) est vrai .

En Java 5, une nouvelle fonctionnalité a été introduite pour sauver la mémoire et d'améliorer les performances des objets de type entier manutentions. objets entiers sont mis en mémoire cache interne et réutilisés par les mêmes objets référencés.

  1. Ceci est applicable pour les valeurs entières dans plage entre -127 à 127 (Max Valeur entière).

  2. Cette mise en cache entier ne fonctionne que sur autoboxing. objets Integer volonté ne pas être mis en cache quand ils sont construits à l'aide du constructeur.

Pour plus de détails ci-dessous Pls passent par lien:

Entier cache en détail

Si nous vérifions le code source de Integer obeject, nous trouverons la source de la méthode de valueOf comme ceci:

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

qui peut expliquer pourquoi les objets Integer, qui dans la plage de -128 (Integer.low) à 127 (Integer.high), sont les mêmes objets référencés au cours de la autoboxing. Et nous pouvons voir qu'il ya une IntegerCache de classe prend en charge l'ensemble du cache Integer, qui est une classe interne statique privée de classe Integer.

Il y a un autre exemple intéressant peut nous aider à comprendre cette situation bizarre:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

      Class cache = Integer.class.getDeclaredClasses()[0]; 
      Field myCache = cache.getDeclaredField("cache"); 
      myCache.setAccessible(true);

      Integer[] newCache = (Integer[]) myCache.get(cache); 
      newCache[132] = newCache[133]; 

      Integer a = 2;
      Integer b = a + a;
      System.out.printf("%d + %d = %d", a, a, b); //The output is: 2 + 2 = 5    

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top