Maison  >  Article  >  Java  >  Compréhension approfondie du boxing et du unboxing en Java

Compréhension approfondie du boxing et du unboxing en Java

高洛峰
高洛峰original
2017-01-24 14:03:451424parcourir

Le problème du boxing et du unboxing automatiques est un problème courant en Java. Aujourd'hui, nous allons examiner certains problèmes liés au boxing et au unboxing. Cet article parle d'abord des éléments les plus élémentaires concernant l'emballage et le déballage, puis examine les questions liées à l'emballage et au déballage qui sont souvent rencontrées lors des entretiens écrits.

1. Qu'est-ce que l'emballage ? Qu’est-ce que le déballage ?

Comme mentionné dans l'article précédent, Java fournit des types de wrapper correspondants pour chaque type de données de base. Quant à la raison pour laquelle il fournit des types de wrapper pour chaque type de données de base, je n'entrerai pas dans les détails ici. les amis intéressés peuvent vérifier les informations pertinentes. Avant Java SE5, si vous souhaitez générer un objet Integer d'une valeur de 10, vous devez procéder comme ceci :

Integer i = new Integer(10);

A partir de Java SE5, la fonctionnalité autoboxing est fournie si vous souhaitez générer. un objet Integer avec une valeur de 10, Pour un objet Integer de 10, faites simplement ceci :

Integer i = 10;

Au cours de ce processus, l'objet Integer correspondant sera automatiquement créé en fonction de la valeur, qui est la boxe.

Alors, qu'est-ce que le déballage ? Comme son nom l'indique, correspondant au boxing, cela signifie convertir automatiquement le type de données de base en type de données de base :

Integer i = 10; //装箱
int n = i; //拆箱

Pour faire simple, boxer signifie convertir automatiquement le type de données de base en type de wrapper ; signifie convertir automatiquement le type de wrapper en type de données de base.

Le tableau suivant présente les types de wrapper correspondant aux types de données de base :

Compréhension approfondie du boxing et du unboxing en Java

2 Comment le boxing et le unboxing sont implémentés

Après avoir compris les concepts de base de la boxe dans la section précédente, apprenons comment la boxe et le unboxing sont implémentés dans cette section.


Prenons la classe Interger comme exemple Regardons un morceau de code :

public class Main {
public static void main(String[] args) {
Integer i = 10;
int n = i;
}
}

Après avoir décompilé le class, nous obtenons le contenu suivant :

Compréhension approfondie du boxing et du unboxing en Java

Il ressort du contenu du bytecode obtenu par décompilation que la méthode valueOf(int) de Integer est automatiquement appelée lors de la boxe. Ce qui est automatiquement appelé lors du déballage est la méthode intValue de Integer.


D'autres sont similaires, comme Double et Character Friends qui n'y croient pas, peuvent l'essayer manuellement.


Ainsi, le processus de mise en œuvre du boxing et du unboxing peut être résumé en une phrase :


Le processus de boxing est implémenté en appelant la méthode valueOf du wrapper, tandis que le unboxing process Le processus est implémenté en appelant la méthode xxxValue du wrapper. (xxx représente le type de données de base correspondant).


3. Questions liées à l'entretien


Bien que la plupart des gens soient clairs sur les concepts d'emballage et de déballage, ils ont rencontré des questions liées à l'emballage lors des entretiens et des tests écrits. La question du boxing et du unboxing ne trouvera peut-être pas de réponse. Voici quelques questions d’entretien courantes liées à l’emballage/au déballage.


1. Quelle est la sortie du code suivant ?

public class Main {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}

Peut-être que certains amis diront que le résultat sera faux, ou que certains amis diront que le résultat sera vrai. Mais en fait, le résultat de sortie est :


vrai

faux

Pourquoi ce résultat se produit-il ? Le résultat montre que i1 et i2 pointent vers le même objet, tandis que i3 et i4 pointent vers des objets différents. À ce stade, il vous suffit de regarder le code source pour connaître la vérité. Le code suivant est l'implémentation spécifique de la méthode valueOf de Integer :

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

Et parmi eux, la classe IntegerCache L'implémentation est :

private static class IntegerCache {
static final int high;
static final Integer cache[];
static {
final int low = -128;
// high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
// Use Long.decode here to avoid invoking methods that
// require Integer&#39;s autoboxing cache to be initialized
int i = Long.decode(integerCacheHighPropValue).intValue();
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - -low);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}

Comme le montrent ces deux morceaux de code, lors de la création d'un Integer objet via la méthode valueOf, si la valeur est dans [-128,127] , une référence à un objet qui existe déjà dans IntegerCache.cache est renvoyée, sinon un nouvel objet Integer est créé ;


Dans le code ci-dessus, les valeurs​​de i1 et i2 sont 100, donc les objets existants seront récupérés directement depuis le cache, donc i1 et i2 pointent vers le même objet, tandis que i3 et i4 pointent respectivement vers des objets différents.


2. Quelle est la sortie du code suivant ?

public class Main {
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}

Certains amis peuvent penser que le résultat de la question ci-dessus est le même, mais en fait ce n'est pas le cas. Le résultat réel de la sortie est :


false

false

En ce qui concerne la raison spécifique, les lecteurs peuvent vérifier l'implémentation de valueOf de la classe Double.

Compréhension approfondie du boxing et du unboxing en Java

Ici, je vais simplement expliquer pourquoi la méthode valueOf de la classe Double utilise une implémentation différente de la méthode valueOf de la classe Integer. C'est simple : le nombre de valeurs entières dans une certaine plage est fini, mais pas les nombres à virgule flottante.


Notez que l'implémentation de la méthode valueOf des classes Integer, Short, Byte, Character et Long est similaire.


L'implémentation de la méthode valueOf de Double et Float est similaire.


3. Quelle est la sortie du code suivant :

public class Main {
public static void main(String[] args) {
Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}

La sortie est :


vrai

vrai

至于为什么是这个结果,同样地,看了Boolean类的源码也会一目了然。下面是Boolean的valueOf方法的具体实现:

public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}

   

而其中的 TRUE 和FALSE又是什么呢?在Boolean中定义了2个静态成员属性:

public static final Boolean TRUE = new Boolean(true);
/**
* The <code>Boolean</code> object corresponding to the primitive
* value <code>false</code>.
*/
public static final Boolean FALSE = new Boolean(false);

   

至此,大家应该明白了为何上面输出的结果都是true了。

4.谈谈Integer i = new Integer(xxx)和Integer i =xxx;这两种方式的区别。

当然,这个题目属于比较宽泛类型的。但是要点一定要答上,我总结一下主要有以下这两点区别:

1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;

2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。

5.下面程序的输出结果是什么?

public class Main {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 2L;
System.out.println(c==d);
System.out.println(e==f);
System.out.println(c==(a+b));
System.out.println(c.equals(a+b));
System.out.println(g==(a+b));
System.out.println(g.equals(a+b));
System.out.println(g.equals(a+h));
}
}

   

先别看输出结果,读者自己想一下这段代码的输出结果是什么。这里面需要注意的是:当 “==”运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。另外,对于包装器类型,equals方法并不会进行类型转换。明白了这2点之后,上面的输出结果便一目了然:

true
false
true
true
true
false
true

第一个和第二个输出结果没有什么疑问。第三句由于 a+b包含了算术运算,因此会触发自动拆箱过程(会调用intValue方法),因此它们比较的是数值是否相等。而对于c.equals(a+b)会先触发自动拆箱过程,再触发自动装箱过程,也就是说a+b,会先各自调用intValue方法,得到了加法运算后的数值之后,便调用Integer.valueOf方法,再进行equals比较。同理对于后面的也是这样,不过要注意倒数第二个和最后一个输出的结果(如果数值是int类型的,装箱过程调用的是Integer.valueOf;如果是long类型的,装箱调用的Long.valueOf方法)。

以上所述是小编给大家介绍的Compréhension approfondie du boxing et du unboxing en Java,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对PHP中文网站的支持!

更多Compréhension approfondie du boxing et du unboxing en Java相关文章请关注PHP中文网!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn