Pourquoi utiliser l'autoboxing et le unboxing en Java?

Autoboxing est la conversion automatique que le compilateur Java fait entre les types primitifs et leur enveloppe d'objet correspondante classe. Par exemple, convertir Un int en un entier, un double en un Double, et ainsi de suite. Si la conversion va dans l'autre sens, c'est appelé unboxing.

alors pourquoi en avons-nous besoin et pourquoi utilisons-nous l'autoboxing et le unboxing en Java?

60
demandé sur Theodoros Chatzigiannakis 2014-12-25 15:59:00

7 réponses

un certain contexte est nécessaire pour comprendre pleinement la raison principale derrière cela.

Primitives versus classes

Primitive variables en Java contiennent des valeurs (un entier, un flottant en double précision nombre binaire, etc). Comme ces valeurs peuvent avoir des longueurs différentes , les variables qui les contiennent peuvent aussi avoir des longueurs différentes (considérons float versus double ).

, d'autre part, variables de classe contiennent des références des instances. Les références sont généralement implémentées en tant que pointeurs (ou quelque chose de très similaire aux pointeurs) dans de nombreuses langues. Ces objets ont généralement la même taille, quelle que soit la taille des instances auxquelles ils se réfèrent.( Object , String , Integer , etc).

cette propriété des variables de classe fait les références qu'elles contiennent interchangeable (dans une certaine mesure). Cela nous permet de faire ce que nous appelons substitution : de manière générale, pour utiliser une instance d'un type particulier comme une instance d'un autre type apparenté (utilisez un String comme un Object , par exemple).

les variables primitives ne sont pas interchangeables de la même manière, ni entre elles, ni avec Object . La raison la plus évidente pour cela (mais pas la seule raison), leur différence de taille. Cela rend les types primitifs incommodes à cet égard, mais nous avons encore besoin d'eux dans le langage (pour des raisons qui se réduisent principalement à la performance).

les Génériques et le type d'effacement de

les types génériques sont des types avec un ou plusieurs paramètres de type (le nombre exact est appelé arity Générique ). Par exemple, l' générique de la définition de type List<T> a un paramètre de type T , qui peut être Object (la production d'un type de béton List<Object> ), String ( List<String> ), Integer ( List<Integer> ) et ainsi de suite.

les types génériques sont beaucoup plus compliqués que les autres. Lorsqu'ils ont été introduits dans Java (après sa sortie initiale), afin d'éviter d'apporter des changements radicaux à la JVM et éventuellement briser la compatibilité avec les binaires plus anciens, les créateurs de Java ont décidé de mettre en œuvre les types génériques de la manière la moins invasive: tous les types concrets de List<T> sont, en fait, compilés à (l'équivalent binaire de) List<Object> (pour les autres types, la limite peut être autre chose que Object , mais vous obtenez le point). L'information Générique d'arité et de paramètre de type est perdue dans ce processus , c'est pourquoi nous l'appelons "1519590920 de type" effacement .

Mettre les deux ensemble

maintenant le problème est la combinaison des réalités ci-dessus: si List<T> devient List<Object> dans tous les cas, alors T doit toujours être un type qui peut être directement assigné à Object . Rien d'autre ne peut pas être permis. Puisque, comme nous l'avons déjà dit, int , float et double ne sont pas interchangeables avec Object , il ne peut pas y avoir de List<int> , List<float> ou List<double> (à moins qu'une mise en œuvre beaucoup plus compliquée de génériques ait existé dans la JVM).

mais Java offre des types comme Integer , Float et Double qui enveloppent ces primitives dans des instances de classe, les rendant effectivement substituables comme Object , donc permettant aux types génériques de travailler indirectement avec les primitives ainsi (parce que vous peut ont List<Integer> , List<Float> , List<Double> et ainsi de suite).

le processus de création d'un Integer à partir d'un int , un Float à partir d'un float et ainsi de suite, est appelé boxe . Le revers est appelé unboxing . Parce que devoir Boxer des primitives à chaque fois que vous voulez les utiliser comme Object est incommode, là sont des cas où le langage fait cela automatiquement - qui s'appelle autoboxing .

131
répondu Theodoros Chatzigiannakis 2015-11-04 09:47:58

Auto Boxing is used pour convertir les types de données primitifs en leurs objets de classe wrapper. La classe Wrapper fournit une large gamme de fonctions à exécuter sur les types primitifs. L'exemple le plus courant est:

int a = 56;
Integer i = a; // Auto Boxing

il est nécessaire en raison de programmeurs faciles à être en mesure d'écrire directement le code et JVM prendra soin de la Boxe et décompression.

Auto Boxing est également pratique lorsque nous travaillons avec java.util.Les types de Collection. Lorsque nous voulons créer une Collection de types primitifs , nous ne pouvons pas créer directement une Collection de type primitif, nous pouvons créer une Collection uniquement D'objets. Par Exemple:

ArrayList<int> al = new ArrayList<int>(); // not supported 

ArrayList<Integer> al = new ArrayList<Integer>(); // supported 
al.add(45); //auto Boxing 

Classes D'Emballage

chacun des 8 types primitifs de Java (byte,short,int,float,char,double,boolean, long) ont une classe D'enveloppe séparée associée à eux. Ces classes Wrapper ont des méthodes prédéfinies pour préformer les opérations utiles sur les types de données primitifs.

utilisation de classes D'emballage 1519120920""

String s = "45";
int a = Integer.parseInt(s); // sets the value of a to 45.

il y a beaucoup de fonctions utiles que les classes D'enrubannage fournissent. Consultez les docs java ici

Unboxing est l'opposé de la boxe automatique où nous convertissons l'objet de la classe wrapper à son type primitif. Cela est fait automatiquement par JVM de sorte que nous pouvons utiliser une les classes d'enrubannage pour certaines opérations et les convertir ensuite de nouveau aux types primitifs que les primitives résultent en un traitement plus rapide. Par Exemple:

Integer s = 45;
int a = s; auto UnBoxing;

dans le cas de Collections qui fonctionnent avec des objets, seul le déverrouillage automatique est utilisé. Voici comment:

ArrayList<Integer> al = new ArrayList<Integer>();
al.add(45);

int a = al.get(0); // returns the object of Integer . Automatically Unboxed . 
13
répondu varun 2014-12-25 14:01:24

les types primitifs (non-objet) ont une justification en efficacité.

les types primitifs int, boolean, double sont des données immédiates, tandis que Object s sont des références. D'où champs (OU variables)

int i;
double x;
Object s;

aurait besoin de mémoire locale 4+8+8 Je ne sais pas. où de l'objet uniquement la référence (adresse) de la mémoire est stockée.

en utilisant les enveloppes D'objet Integer, Double et d'autres, on pourrait introduisez une expression indirecte, référence à une instance entière / Double dans la mémoire tas.

pourquoi la boxe est-elle nécessaire?

C'est une question de portée relative. Dans un futur java, il est prévu d'être capable d'avoir un ArrayList<int> , levant des types primitifs.

réponse: pour l'instant un ArrayList travaille seulement pour L'objet, réservant la place pour une référence d'objet, et gestion de la collecte des ordures également. Par conséquent les types génériques sont des enfants objet. Donc si on voulait un tableau de valeurs flottantes, il fallait envelopper un double dans un objet Double.

ici Java diffère du C++ traditionnel avec ses modèles: les classes C++ vector<string>, vector<int> créeraient deux produits de compilation. Java design est allé pour avoir un ArrayList.classe, n'ayant pas besoin pour chaque paramètre type Un nouveau produit compilé.

donc sans boxe pour objecter il faudrait compiler des classes pour chaque occurrence d'un type de paramètre. Dans le concret: chaque collection ou classe de conteneur aurait besoin d'une version pour objet, int, double, booléen. La version pour objet gérerait toutes les classes d'enfants.

en fait, la nécessité d'une telle diversification existait déjà en Java SE pour IntBuffer, CharBuffer, DoubleBuffer, ... qui opèrent sur int, char, double. Il a été résolu d'une manière hacky par générer ces sources à partir d'une source commune.

5
répondu Joop Eggen 2014-12-25 14:17:34

à partir de JDK 5, java a ajouté deux fonctions importantes: l'autoboxing et l'autounboxing. l'autoboxing est le processus par lequel un type primitif est automatiquement encapsulé dans l'équivalent wrapper chaque fois qu'un tel objet est nécessaire. Vous n'avez pas à construire explicitement un objet. auto-unboxing est le processus par lequel la valeur d'un objet encapsulé est automatiquement extraite d'un type de wrapper lorsque sa valeur est requise. Vous n'avez pas besoin d'appeler une méthode telle que intValue() ou doubleValue() .

L'ajout de l'autoboxing et auto-unboxing grandement simplifie l'écriture des algorithmes , en éliminant l'appât manuellement boxing et unboxing de valeurs. Il est également utile de éviter les erreurs . Il est également très important pour génériques , qui opèrent uniquement sur des objets. Enfin, l'autoboxing facilite le travail avec le Collections Framework .

3
répondu Amarildo 2017-07-02 20:42:26

pourquoi avons-nous (un)la boxe?

pour rendre le code d'écriture où nous mélangeons primitives et leurs alternatives orientées objet (OO) plus confortable/moins verbeux.

pourquoi avons-nous des primitifs et leurs alternatives OO?

Les types primitifs

ne sont pas des classes (contrairement à C#), donc ils ne sont pas des sous-classes de Object et ne peuvent pas être dépassés.

nous avons des primitives comme int pour des raisons de performance, et les Object alternatives comme Integer pour les avantages de la programmation OO, et comme point mineur, pour avoir un bon emplacement pour les constantes d'utilité et les méthodes (entier.MAX_VALUE et Integer.toString(int) ).

les avantages de L'OO sont plus facilement visibles avec les génériques ( List<Integer> ), mais ne sont pas limités à cela, par exemple:

Number getMeSome(boolean wantInt) {

    if (wantInt) {
        return Integer.MAX_VALUE;
    } else {
        return Long.MAX_VALUE;
    }
}
2
répondu hoijui 2014-12-25 13:33:16

parce qu'ils sont différents types, et comme une commodité. La Performance est probablement la raison d'avoir des types primitifs.

1
répondu Scott Hunter 2014-12-25 13:03:43

certaines structures de données ne peuvent accepter que des objets, pas de types primitifs.

exemple: la clé dans une HashMap.

voir cette question pour plus de détails: HashMap et int comme clé

il y a d'autres bonnes raisons, comme un champ" int " dans une base de données, qui pourrait être nul. Un int en Java ne peut pas être null ; une référence entière peut l'être. L'Autoboxing et le unboxing fournissent avec une facilité pour éviter l'écriture étrangère code dans les conversions d'avant en arrière.

1
répondu Gabriel 2017-05-23 12:34:50