Dans cet article, l'auteur vous présentera une fonctionnalité très importante et intéressante dans Java, qui est la boxe et un déballage automatique, et interpréter les principes de la boxe et de la déballage automatique à partir du code source. En même temps, cette fonctionnalité laisse également un piège. Si les développeurs ne font pas attention, ils tomberont facilement dans ce piège.
Autoboxing
définition
Lors de la rédaction de programmes Java, les gens définissent souvent un objet entier de la manière suivante:
Entier i = 100;
À partir du code ci-dessus, vous pouvez savoir que I est une référence de type entier et 100 est le type de données de base en Java (type de données primitif). Cette méthode de transmission directe d'un type de données de base à sa classe de wrapper correspondante est la boxe automatique.
Dans JDK 1.5, la boxe automatique a été introduite pour la première fois. Avant JDK 1.5, si vous souhaitez définir un objet entier avec une valeur de 100, vous devez le faire:
Entier i = nouvel entier (100);
principe
Faisons un point d'arrêt au code ci-dessus "entier i = 100;" et suivez-le.
Ensuite, nous pouvons voir que le programme saute sur la méthode de valeur de (int i) de la classe entière.
/ ** * Renvoie une instance <tt> entier </tt> représentant la valeur spécifiée * <TT> int </tt>. * Si une nouvelle instance <TT> entier </tt> n'est pas requise, cette méthode * doit généralement être utilisée en préférence au constructeur * {@Link #Integer (int)}, car cette méthode est susceptible de donner * des performances d'espace et de temps significativement meilleures en mettant en cache * les valeurs fréquemment demandées. * * @param I une valeur <code> int </code>. * @return A <TT> INTEGER </TT> Instance représentant <TT> I </TT>. * @Since 1.5 * / public static entier STATIQUE VALEUR (int i) {if (i> = -128 && i <= IntegerCache.high) return IntegerCache.cache [i + 128]; sinon renvoie un nouvel entier (i); }En d'autres termes, l'emballage est JDK qui vous aide à terminer l'appel à Integer.ValueOf (100).
Déballage
définition
Integer Integer100 = 100; int int100 = Integer100;
À partir du code ci-dessus, vous pouvez voir qu'Integer100 est une référence à Type Integer, et INT100 est un type de données primitif de type int. Cependant, nous pouvons attribuer un objet de type entier à une variable de son type de données d'origine correspondant. C'est un déballage.
Unboxing est l'opposé de l'emballage. La boxe est une variable qui attribue un type de données primitif à la classe encapsulée correspondante. Débrancher signifie attribuer une variable d'une classe encapsulée à une variable du type de données d'origine correspondant. Les noms de l'emballage et du déballage sont également très appropriés.
principe
Je crois que tout le monde a deviné ce que JDK a fait pour nous pendant le processus de déballage. Prouver notre conjecture à travers des expériences.
Définissez un point d'arrêt sur la deuxième ligne du code ci-dessus, c'est-à-dire définir un point d'arrêt sur "int int100 = Integer100;" et suivez-le.
Nous pouvons voir que le programme saute sur la méthode IntValue () d'Integer.
/ ** * Renvoie la valeur de ce <code> entier </code> en tant que * <code> int </code>. * / public int intValue () {return Value; }Autrement dit, JDK nous aide à terminer l'appel à la méthode IntValue (). Pour l'expérience ci-dessus, il s'agit d'appeler la méthode IntValue () d'Integer100 et d'attribuer sa valeur de retour à INT100.
Étendu
Expérience 1
Integer Integer400 = 400; int int400 = 400; System.out.println (Integer400 == int400);
Dans la troisième ligne du code ci-dessus, Integer400 et INT400 exécutent le == run. Et ces deux sont différents types de variables. Les emballages Integer400 ou l'emballage INT400 sont-ils? Quels sont les résultats de l'opération?
== L'opération consiste à déterminer si les adresses de deux objets sont égales ou si les valeurs des deux types de données de base sont égales. Par conséquent, il est facile de déduire que si Integer400 n'est pas sous forme, cela signifie que les valeurs des deux types de base sont comparées et que le résultat en cours doit être vrai pour le moment; Si INT400 est emballé, cela signifie que les adresses des deux objets sont égales et que le résultat en cours d'exécution doit être faux pour le moment. (Quant à savoir pourquoi l'auteur les attribue à 400, il est lié aux pièges qui seront discutés plus loin).
Notre résultat en cours d'exécution est vrai. C'était donc un déballage Integer400. Les résultats du suivi du code le prouvent.
Expérience 2
Integer Integer100 = 100; int int100 = 100; System.out.println (Integer100.equals (int100));
Dans la troisième ligne du code ci-dessus, le paramètre de la méthode d'Integer100 équivaut à Int100. Nous savons que les paramètres de la méthode Equals sont un objet, pas le type de données de base, donc ici, il doit être emballé INT100. Les résultats du suivi du code le prouvent.
En fait, si le type de paramètre dans une méthode est le type de données d'origine et que le type de paramètre transmis est sa classe d'encapsulation, il sera automatiquement déballé; En conséquence, si le type de paramètre dans une méthode est le type d'encapsulation et que le type de paramètre transmis est son type de données d'origine, il sera automatiquement encadré.
Expérience 3
Integer Integer100 = 100; int int100 = 100; long long200 = 200l; System.out.println (Integer100 + int100); System.out.println (Long200 == (Integer100 + int100)); System.out.println (Long200.Equaux (Integer100 + int100));
Dans la première expérience, nous avons appris que lorsqu'un type de données de base effectue un fonctionnement == avec la classe d'encapsulation, la classe d'encapsulation sera déballée. Et si +, -,, *, /? Nous pouvons savoir dans cette expérience.
Si + l'opération, le type de données sous-jacent sera encadré, alors:
• En ligne 4, Integer100 + INT100 obtiendra un objet O de type entier et de la valeur 200, et exécutera la méthode toString () de cet objet et de cette sortie "200";
• Dans la ligne 5, Integer100 + INT100 obtiendra un objet O de type entier et une valeur de 200. L'opération == compare cet objet avec un objet Long200. De toute évidence, FALSE sera sorti;
• Dans la ligne 6, Integer100 + INT100 obtiendra un objet O de type entier et de la valeur 200. La méthode égale de Long compare Long200 avec O, car les deux sont des classes encapsulées de types différents, donc la sortie est fausse;
Si + l'opération, la classe d'encapsulation sera non sous boîte, alors:
• En ligne 4, Integer100 + INT100 obtiendra un type de données de base B de Type INT et Valeur 200, puis Box B pour obtenir O, exécutez la méthode TOSTRING () de cet objet, et la sortie "200";
• Dans la ligne 5, Integer100 + INT100 obtiendra un type de données de base B1 de Type INT et Valeur 200. L'opération == déborde Long200 pour obtenir B2. Évidemment B1 == B2, et sortira True;
• Dans la ligne 6, Integer100 + INT100 obtiendra un type de données de base B de Type INT et Valeur 200. Long est égal aux boîtes de méthode B, mais la boxe se traduit par un objet O de type entier, car O et Long200 sont des objets de différents types, donc la sortie est fausse;
Le résultat de la course au programme est:
200
vrai
FAUX
Par conséquent, la deuxième spéculation est correcte, c'est-à-dire que la classe d'encapsulation sera non sous boîte pendant l'opération +.
piège
Piège 1
Entier entier100 = null;
int int100 = Integer100;
Ces deux lignes de code sont complètement légales et peuvent être compilées complètement, mais lors de l'exécution, une exception de pointeur nul sera lancée. Parmi eux, Integer100 est un objet de type entier, qui peut bien sûr pointer vers Null. Mais dans la deuxième ligne, Integer100 sera non déballé, c'est-à-dire que la méthode intValue () sera exécutée sur un objet nul, et bien sûr, une exception de pointeur nul sera lancée. Par conséquent, lors de la déballage, vous devez prêter une attention particulière à savoir si l'objet de classe encapsulé est nul.
Piège 2
Entier i1 = 100;
Entier i2 = 100;
Entier i3 = 300;
Entier i4 = 300;
System.out.println (i1 == i2);
System.out.println (i3 == i4);
Parce que i1, i2, i3 et i4 sont tous des types entiers, nous pensons que les résultats en cours d'exécution devraient être faux. Cependant, le résultat réel en cours d'exécution est "System.out.println (i1 == i2);" Ce qui est vrai, mais "System.out.println (i3 == i4);" ce qui est faux. Cela signifie que les références des deux types entiers, I1 et I2, indiquent le même objet, tandis que I3 et I4, indiquent différents objets. Pourquoi? Ne sont-ils pas tous appelés la méthode Integer.Valueof (int i)?
Jetons un coup d'œil à la méthode INTEGER.VALUEOF (INT I).
/ ** * Renvoie une instance <tt> entier </tt> représentant la valeur spécifiée * <TT> int </tt>. * Si une nouvelle instance <TT> entier </tt> n'est pas requise, cette méthode * doit généralement être utilisée en préférence au constructeur * {@Link #Integer (int)}, car cette méthode est susceptible de donner * des performances d'espace et de temps significativement meilleures en mettant en cache * les valeurs fréquemment demandées. * * @param I une valeur <code> int </code>. * @return A <TT> INTEGER </TT> Instance représentant <TT> I </TT>. * @Since 1.5 * / public static entier STATIQUE VALEUR (int i) {if (i> = -128 && i <= IntegerCache.high) return IntegerCache.cache [i + 128]; sinon renvoie un nouvel entier (i); }Nous pouvons voir que lorsque i> = - 128 et i <= IntegerCache.high, le IntegerCache.cache [i + 128] est renvoyé directement. Parmi eux, IntegerCache est une classe statique interne d'Integer, et son code d'origine est le suivant:
classe statique privée IntegerCache {statique final int high; Cache entier final statique []; statique {final int low = -128; // La valeur élevée peut être configurée par la propriété int h = 127; if (IntegerCacheHighPropValue! = null) {// Utilisez long.decode ici pour éviter d'invoquer des méthodes qui // nécessitent le cache d'autoboxing d'Integer pour être initialisé int i = long.decode (IntegerCacheHighPropValue) .IntValue (); i = math.max (i, 127); // La taille maximale du tableau est Integer.max_value h = math.min (i, Integer.max_value - -low); } high = h; cache = nouvel entier [(élevé - bas) + 1]; int j = bas; pour (int k = 0; k <cache.length; k ++) cache [k] = nouveau entier (j ++); } private IntegerCache () {}}Nous pouvons clairement voir qu'IntegerCache a un cache variable de membre statique, qui est un tableau avec 256 éléments. Le cache est également initialisé dans IntegerCache, c'est-à-dire que le i-th element est un objet entier avec une valeur de I-128. -128 à 127 sont les objets entiers les plus couramment utilisés, et cette approche améliore également considérablement les performances. C'est aussi à cause de cela que "Integeri1 = 100; Integer I2 = 100;", I1 et I2 obtiennent le même objet.
En comparant la deuxième expérience dans l'extension, nous avons appris que lorsque la classe d'encapsulation est en cours d'exécution == avec le type de base, la classe d'encapsulation se déroulera et le résultat de déballage est comparé au type de base; Alors que lorsque les deux classes d'encapsulation fonctionnent == avec les autres objets, ils comparent les adresses des deux objets, c'est-à-dire pour déterminer si les deux références pointent vers le même objet.
L'article ci-dessus discute brièvement de l'emballage et de la déballage automatique Java et ses pièges sont tout le contenu que je partage avec vous. J'espère que cela pourra vous donner une référence et j'espère que vous pourrez soutenir Wulin.com plus.