Che cos’è il pugilato e l’unboxing e quali sono i trade off?

Sto cercando una risposta chiara, concisa e accurata.

Idealmente come la risposta vera e propria, anche se i link a buone spiegazioni sono ben accetti.

I valori in scatola sono strutture di dati che sono involucri minimi attorno ai tipi primitivi *. I valori in scatola vengono in genere archiviati come puntatori agli oggetti nell’heap .

Pertanto, i valori in box utilizzano più memoria e richiedono almeno due ricerche di memoria per accedere: una volta per ottenere il puntatore e un’altra per seguire quel puntatore alla primitiva. Ovviamente questo non è il tipo di cosa che vuoi nei tuoi loop interiori. D’altra parte, i valori in scatola di solito giocano meglio con altri tipi nel sistema. Poiché sono strutture di dati di prima class nella lingua, hanno i metadati e la struttura previsti che hanno altre strutture di dati.

In Java e Haskell le raccolte generiche non possono contenere valori non condivisi. Le raccolte generiche in .NET possono contenere valori non condivisi senza penalità. Laddove i generici di Java sono utilizzati solo per il controllo del tipo in fase di compilazione, .NET genererà classi specifiche per ogni tipo generico istanziato in fase di esecuzione .

Java e Haskell hanno matrici unboxed, ma sono nettamente meno convenienti delle altre collezioni. Tuttavia, quando è necessario un picco di prestazioni, vale la pena di fare un piccolo inconveniente per evitare il sovraccarico di boxe e unboxing.

* Per questa discussione, un valore primitivo è qualsiasi che può essere memorizzato nello stack di chiamate , piuttosto che memorizzato come puntatore a un valore sull’heap. Spesso sono solo i tipi di macchina (int, float, ecc.), Le strutture e talvolta gli array di dimensioni statiche. .NET-land li chiama tipi di valore (al contrario dei tipi di riferimento). I popoli Java li chiamano tipi primitivi. Haskellions li chiama semplicemente non in scatola.

** Mi sto concentrando anche su Java, Haskell e C # in questa risposta, perché è quello che so. Per quello che vale, Python, Ruby e Javascript hanno tutti valori esclusivamente in box. Questo è anche noto come approccio “Tutto è un object” ***.

*** Caveat: Un compilatore / JIT sufficientemente avanzato in alcuni casi può effettivamente rilevare che un valore che è semanticamente in scatola quando si guarda all’origine, può tranquillamente essere un valore unboxed in fase di esecuzione. In sostanza, grazie a implementatori linguistici brillanti, le tue scatole sono a volte gratuite.

da C # 3.0 In breve :

La boxe è l’atto di trasmettere un tipo di valore in un tipo di riferimento:

 int x = 9; object o = x; // boxing the int 

unboxing è … il contrario:

 // unboxing o object o = 9; int x = (int)o; 

Boxing & Unboxing è il processo di conversione di un valore primitivo in una class wrapper object oriented (boxing) o conversione di un valore da una class wrapper object oriented al valore primitivo (unboxing).

Ad esempio, in java, potrebbe essere necessario convertire un valore int in un numero Integer (boxing) se si desidera archiviarlo in una Collection perché le primitive non possono essere archiviate in una Collection , solo oggetti. Ma quando vuoi rimuoverlo dalla Collection potresti voler ottenere il valore come int e non come un Integer modo da poterlo rimuovere.

Il pugilato e l’unboxing non sono intrinsecamente cattivi , ma è un compromesso. A seconda dell’implementazione della lingua, può essere più lenta e più intensiva della memoria rispetto all’utilizzo di primitive. Tuttavia, potrebbe anche consentire di utilizzare strutture di dati di livello superiore e ottenere una maggiore flessibilità nel codice.

Al giorno d’oggi, è più comunemente discusso nel contesto della funzionalità “autoboxing / autounboxing” di Java (e di altre lingue). Ecco una spiegazione java centrica di autoboxing .

In. Net:

Spesso non è ansible fare affidamento su quale tipo di variabile una funzione consumerà, quindi è necessario utilizzare una variabile object che si estenda dal minimo comune denominatore – in. Net questo è l’ object .

Comunque object è una class e memorizza i suoi contenuti come riferimento.

 List notBoxed = new List { 1, 2, 3 }; int i = notBoxed[1]; // this is the actual value List boxed = new List { 1, 2, 3 }; int j = (int) boxed[1]; // this is an object that can be 'unboxed' to an int 

Mentre entrambi contengono le stesse informazioni, la seconda lista è più grande e più lenta. Ogni valore nel secondo elenco è in realtà un riferimento a un object che contiene l’ int .

Questo è chiamato in scatola perché l’ int è avvolto object . Quando viene restituito il cast, int è unboxed – riconvertito al suo valore.

Per i tipi di valore (cioè tutte le structs ) questo è lento e potenzialmente utilizza molto più spazio.

Per i tipi di riferimento (vale a dire tutte le classs ) questo è molto meno un problema, in quanto sono comunque memorizzati come riferimento.

Un ulteriore problema con un valore di tipo boxed è che non è ovvio che hai a che fare con la scatola, piuttosto che con il valore. Quando si confrontano due structs si confrontano i valori, ma quando si confrontano due classs (per impostazione predefinita) si sta confrontando il riferimento, ovvero si tratta della stessa istanza?

Questo può essere fonte di confusione quando si tratta di tipi di valore in box:

 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 

È facile da aggirare:

 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 

Tuttavia è un’altra cosa da fare attenzione quando si tratta di valori in scatola.

Le raccolte generiche di .NET FCL:

 List Dictionary SortedDictionary Stack Queue LinkedList 

sono stati tutti progettati per superare i problemi di prestazioni di boxe e unboxing nelle precedenti implementazioni di raccolta.

Per ulteriori informazioni, vedere il capitolo 16, CLR tramite C # (2a edizione) .

La boxe è il processo di conversione di un tipo di valore in un tipo di riferimento.

Unboxing è la conversione di un tipo di riferimento in un tipo di valore.

 EX: int i=123; object o=i;// Boxing int j=(int)o;// UnBoxing 

Il tipo di valore è:
int, char e strutture, enumerazioni. I Reference Type sono: Classi, interfacce, matrici, stringhe e oggetti

Boxing e Unboxing facilitano i tipi di valore da trattare come oggetti. Boxing significa convertire un valore in un’istanza del tipo di riferimento dell’object. Ad esempio, Int è una class e int è un tipo di dati. La conversione di int in Int è un’esemplificazione del pugilato, mentre la conversione di Int in int è unboxing. Il concetto aiuta nella raccolta dei rifiuti, Unboxing, d’altra parte, converte il tipo di object in tipo di valore.

 int i=123; object o=(object)i; //Boxing o=123; i=(int)o; //Unboxing. 

Come qualsiasi altra cosa, l’autoboxing può essere problematico se non usato con attenzione. Il classico è finire con NullPointerException e non essere in grado di rintracciarlo. Anche con un debugger. Prova questo:

 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; } }