Qu'est-boxing et unboxing et quels sont les compromis?
je cherche une réponse claire, concise et précise.
idéalement comme la réponse réelle, bien que les liens vers de bonnes explications soient les bienvenus.
8 réponses
Boîte valeurs sont structures de données que sont minimes wrappers autour de types primitifs *. Les valeurs en encadré sont typiquement stockées comme des pointeurs vers des objets sur le tas .
ainsi, les valeurs boxées utilisent plus de mémoire et prennent au moins deux lookups mémoire pour accéder: une fois pour obtenir le pointeur, et une autre pour suivre ce pointeur à la primitive. Évidemment, ce n'est pas le genre de chose que vous voulez dans votre boucles internes. D'un autre côté, les valeurs encadrées jouent généralement mieux avec d'autres types dans le système. Comme il s'agit de structures de données de premier ordre dans la langue, elles ont les métadonnées et la structure attendues des autres structures de données.
en Java et Haskell les collections génériques ne peuvent pas contenir de valeurs non encadrées. Les collections génériques dans .NET peuvent contenir des valeurs non encadrées sans pénalité. Lorsque les génériques de Java ne sont utilisés que pour la vérification de type de compilation, .NET génère des classes spécifiques pour chaque type générique instancié au moment de l'exécution .
Java et Haskell ont des tableaux non encadrés, mais ils sont nettement moins pratiques que les autres collections. Cependant, quand la performance de pointe est nécessaire, il vaut la peine d'un petit inconvénient pour éviter la surabondance de la boxe et de la unboxing.
* pour cette discussion, une valeur primitive est n'importe quelle valeur qui peut être stockée sur la pile d'appels , plutôt que stocké comme un indicateur d'une valeur sur le tas. Souvent, c'est juste les types de machines (ints, floats, etc), les structures, et parfois les tableaux de taille statique. .NET - appels terrestres les types de valeur (par opposition aux types de référence). Les gens de Java les appellent des types primitifs. Haskellions les appelle juste Non boxés.
* * je me concentre aussi sur Java, Haskell, et C# dans cette réponse, parce que c'est ce que je sais. Pour ce que ça vaut, Python, Ruby et Javascript ont tous exclusivement coffret valeurs. C'est ce qu'on appelle aussi l'approche "tout est un objet"***.
* * * mise en garde: un compilateur / JIT suffisamment avancé peut dans certains cas réellement détecter qu'une valeur qui est encadré sémantiquement en regardant la source, peut en toute sécurité être une valeur non encadrée à l'exécution. Par essence, grâce à de brillants langagiers, vos boîtes sont parfois gratuites.
à partir de de C# 3.0, En un Mot :
la boxe est l'acte de lancer une valeur type dans un type de référence:
int x = 9;
object o = x; // boxing the int
unboxing est... l'inverse:
// unboxing o
object o = 9;
int x = (int)o;
Boxing & unboxing est le processus de conversion d'une valeur primitive en une classe d'emballage orientée objet (boxing), ou de conversion d'une valeur d'une classe d'emballage orientée objet en une valeur primitive (unboxing).
par exemple, en java, vous pouvez avoir besoin de convertir une valeur int
en une valeur Integer
(boxe) si vous voulez la stocker dans un Collection
parce que les primitives ne peuvent pas être stockées dans un Collection
, seulement des objets. Mais lorsque vous souhaitez l'obtenir de retour de la Collection
vous voulez pour obtenir la valeur comme une int
et non un Integer
donc, vous unbox.
Boxing et unboxing est pas, en soi mauvais , mais c'est un compromis. Selon l'implémentation du langage, il peut être plus lent et plus exigeant en mémoire que l'utilisation de primitives. Cependant, il peut également vous permettre d'utiliser des structures de données de niveau supérieur et d'obtenir une plus grande flexibilité dans votre code.
de nos jours, il est le plus souvent discuté dans le contexte de la fonctionnalité "autoboxing/autounbox" de Java (et d'autres langues). Voici un java centrée sur l'explication de l'autoboxing .
In .Net:
souvent, vous ne pouvez pas compter sur ce que le type de variable une fonction consommera, donc vous devez utiliser une variable objet qui s'étend à partir du plus petit dénominateur commun - in .Net c'est object
.
Toutefois object
est une classe et stocke son contenu comme une référence.
List<int> notBoxed = new List<int> { 1, 2, 3 };
int i = notBoxed[1]; // this is the actual value
List<object> boxed = new List<object> { 1, 2, 3 };
int j = (int) boxed[1]; // this is an object that can be 'unboxed' to an int
bien que ces deux listes contiennent la même information, la deuxième liste est plus longue et plus lente. Chaque valeur de la la deuxième liste est en fait une référence à un object
qui contient le int
.
cela s'appelle boxed parce que le int
est enveloppé par le object
. Lorsque son moulage en arrière le int
est non boxé - converti de nouveau à sa valeur.
pour les types de valeurs (i.e. tous structs
) c'est lent, et utilise potentiellement beaucoup plus d'espace.
pour les types de référence (c'est-à-dire tous les classes
) problème, car ils sont stockés comme référence de toute façon.
un autre problème avec un type de valeur en boîte est qu'il n'est pas évident que vous ayez affaire à la boîte, plutôt qu'à la valeur. Quand vous comparez deux structs
alors vous comparez des valeurs, mais quand vous comparez deux classes
alors (par défaut) vous comparez la référence - c.-à-d. Est-ce la même instance?
cela peut prêter à confusion lorsqu'il s'agit de types de valeurs en encadré:
int a = 7;
int b = 7;
if(a == b) // Evaluates to true, because a and b have the same value
object c = (object) 7;
object d = (object) 7;
if(c == d) // Evaluates to false, because c and d are different instances
C'est facile à contourner:
if(c.Equals(d)) // Evaluates to true because it calls the underlying int's equals
if(((int) c) == ((int) d)) // Evaluates to true once the values are cast
cependant, c'est une autre chose d'être prudent lorsqu'il s'agit de valeurs encadrées.
.NET FCL générique collections:
List<T>
Dictionary<TKey, UValue>
SortedDictionary<TKey, UValue>
Stack<T>
Queue<T>
LinkedList<T>
ont tous été conçus pour surmonter les problèmes de performance de la boxe et le non-boxe dans les mises en œuvre de collection précédentes.
pour plus de détails, voir le chapitre 16, CLR via C# (2e édition) .
la Boxe est le processus de conversion d'un type de valeur dans un type de référence.
Unboxing est la conversion d'un type de référence en un type de valeur.
EX: int i=123;
object o=i;// Boxing
int j=(int)o;// UnBoxing
le Type de valeur est:
int, char et des structures,énumérations.
Type de référence sont:
Classes, interfaces,tableaux, chaînes et objets
Boxing et unboxing facilite les types de valeur à être traitées comme des objets. Boxing signifie convertir une valeur en une instance du type de référence de l'objet. Par exemple, Int
est une classe et int
est un type de données. La conversion de int
en Int
est un exemple de boxe, tandis que la conversion de Int
en int
est un Boxing. Le concept aide dans la collecte des ordures, Unboxing, d'autre part, convertit le type d'objet en type de valeur.
int i=123;
object o=(object)i; //Boxing
o=123;
i=(int)o; //Unboxing.
comme toute autre chose, l'autoboxing peut être problématique s'il n'est pas utilisé avec soin. Le classique est de se retrouver avec une NullPointerException et ne pas être en mesure de le traquer. Même avec un débogueur. Essayez ceci:
public class TestAutoboxNPE
{
public static void main(String[] args)
{
Integer i = null;
// .. do some other stuff and forget to initialise i
i = addOne(i); // Whoa! NPE!
}
public static int addOne(int i)
{
return i + 1;
}
}