Ich suche eine klare, präzise und genaue Antwort.
Idealerweise als eigentliche Antwort, obwohl Links zu guten Erklärungen willkommen sind.
Ich suche eine klare, präzise und genaue Antwort.
Idealerweise als eigentliche Antwort, obwohl Links zu guten Erklärungen willkommen sind.
language-but-not-type-agnostic
?static-language-agnostic
? Ich bin nicht sicher, ob SO die Unterscheidung braucht; könnte aber eine gute Frage für Meta sein.Antworten:
Boxed-Werte sind Datenstrukturen, bei denen es sich um minimale Wrapper um primitive Typen * handelt. Boxed-Werte werden normalerweise als Zeiger auf Objekte auf dem Heap gespeichert .
Daher verwenden Box-Werte mehr Speicher und benötigen mindestens zwei Speichersuchen, um darauf zuzugreifen: einmal, um den Zeiger abzurufen, und einmal, um diesem Zeiger auf das Grundelement zu folgen. Offensichtlich ist dies nicht die Art von Dingen, die Sie in Ihren inneren Schleifen wollen. Auf der anderen Seite spielen Box-Werte normalerweise besser mit anderen Typen im System. Da es sich um erstklassige Datenstrukturen in der Sprache handelt, verfügen sie über die erwarteten Metadaten und Strukturen anderer Datenstrukturen.
In Java und Haskell dürfen generische Sammlungen keine Werte ohne Box enthalten. Generische Sammlungen in .NET können Werte ohne Box ohne Strafen enthalten. Wenn Javas Generika nur zur Überprüfung des Typs zur Kompilierungszeit verwendet werden, generiert .NET für jeden zur Laufzeit instanziierten generischen Typ bestimmte Klassen .
Java und Haskell haben Arrays ohne Box, aber sie sind deutlich weniger praktisch als die anderen Sammlungen. Wenn jedoch Spitzenleistung benötigt wird, ist es ein wenig unangenehm, den Aufwand für das Boxen und Entpacken zu vermeiden.
* In dieser Diskussion ist ein primitiver Wert ein beliebiger Wert, der auf dem Aufrufstapel gespeichert werden kann , anstatt als Zeiger auf einen Wert auf dem Heap gespeichert zu werden. Häufig sind dies nur die Maschinentypen (Ints, Floats usw.), Strukturen und manchmal Arrays mit statischer Größe. .NET-land nennt sie Werttypen (im Gegensatz zu Referenztypen). Java-Leute nennen sie primitive Typen. Haskellions nennen sie einfach unboxed.
** Ich konzentriere mich in dieser Antwort auch auf Java, Haskell und C #, weil ich das weiß. Python, Ruby und Javascript haben ausschließlich Box-Werte. Dies wird auch als "Alles ist ein Objekt" -Ansatz *** bezeichnet.
*** Vorsichtsmaßnahme: Ein ausreichend fortgeschrittener Compiler / JIT kann in einigen Fällen tatsächlich erkennen, dass ein Wert, der beim Betrachten der Quelle semantisch eingerahmt ist, zur Laufzeit sicher ein Wert ohne Box sein kann. Im Wesentlichen sind Ihre Boxen dank brillanter Sprachimplementierer manchmal kostenlos.
quelle
aus C # 3.0 Auf den Punkt gebracht :
quelle
Beim Boxen und Entpacken wird ein primitiver Wert in eine objektorientierte Wrapper-Klasse konvertiert (Boxen) oder ein Wert von einer objektorientierten Wrapper-Klasse zurück in den primitiven Wert konvertiert (Unboxing).
In Java müssen Sie beispielsweise möglicherweise einen
int
Wert in einInteger
(Boxing) konvertieren, wenn Sie ihn in einem speichern möchten,Collection
da Grundelemente nicht in einemCollection
einzigen Objekt gespeichert werden können . Aber wenn Sie es wieder aus demCollection
herausholen möchten, möchten Sie möglicherweise den Wert alsint
und nicht als erhalten,Integer
damit Sie ihn entpacken.Boxen und Unboxen ist nicht von Natur aus schlecht , aber es ist ein Kompromiss. Abhängig von der Sprachimplementierung kann es langsamer und speicherintensiver sein als nur die Verwendung von Grundelementen. Möglicherweise können Sie jedoch auch Datenstrukturen auf höherer Ebene verwenden und eine größere Flexibilität in Ihrem Code erzielen.
Heutzutage wird es am häufigsten im Zusammenhang mit der "Autoboxing / Autounboxing" -Funktion von Java (und anderen Sprachen) diskutiert. Hier ist eine Java-zentrierte Erklärung für Autoboxing .
quelle
In .Net:
Oft können Sie sich nicht darauf verlassen, welchen Variablentyp eine Funktion verbraucht. Daher müssen Sie eine Objektvariable verwenden, die sich vom kleinsten gemeinsamen Nenner aus erstreckt - in .Net ist dies
object
.Ist
object
jedoch eine Klasse und speichert ihren Inhalt als Referenz.Während beide die gleichen Informationen enthalten, ist die zweite Liste größer und langsamer. Jeder Wert in der zweiten Liste ist tatsächlich eine Referenz auf einen
object
, der die enthältint
.Dies wird als Box bezeichnet, da das
int
von der umwickelt wirdobject
. Wenn es zurückgeworfen wird, wird das nichtint
verpackt - wieder in seinen Wert konvertiert.Für Werttypen (dh alle
structs
) ist dies langsam und benötigt möglicherweise viel mehr Speicherplatz.Für Referenztypen (dh alle
classes
) ist dies weitaus weniger problematisch, da sie ohnehin als Referenz gespeichert werden.Ein weiteres Problem mit einem Boxed-Value-Typ ist, dass es nicht offensichtlich ist, dass Sie sich mit der Box und nicht mit dem Wert befassen. Wenn Sie zwei vergleichen, vergleichen
structs
Sie Werte, aber wenn Sie zwei vergleichen, vergleichen Sieclasses
(standardmäßig) die Referenz - dh handelt es sich um dieselbe Instanz?Dies kann beim Umgang mit Boxed-Value-Typen verwirrend sein:
Es ist einfach zu umgehen:
Es ist jedoch eine andere Sache, auf die Sie beim Umgang mit Boxwerten achten müssen.
quelle
Object
implementiert den Gleichheitsoperator nicht, aber Klassentypen können mit demIs
Operator verglichen werden. kann umgekehrtInt32
mit dem Gleichheitsoperator verwendet werden, aber nichtIs
. Diese Unterscheidung macht viel klarer, welche Art von Vergleich durchgeführt wird.Boxing
ist der Prozess der Konvertierung eines Werttyps in einen Referenztyp. WährendUnboxing
die Umwandlung eines Referenztyps in einen Werttyp ist.Werttypen sind:
int
,char
undstructures
,enumerations
. Referenztypen sind:Classes
,interfaces
,arrays
,strings
undobjects
quelle
Die generischen .NET FCL-Sammlungen:
wurden alle entwickelt, um die Leistungsprobleme beim Ein- und Auspacken in früheren Sammlungsimplementierungen zu überwinden.
Weitere Informationen finden Sie in Kapitel 16, CLR über C # (2. Ausgabe) .
quelle
Durch das Ein- und Auspacken können Werttypen als Objekte behandelt werden. Boxen bedeutet, einen Wert in eine Instanz des Objektreferenztyps zu konvertieren. Ist beispielsweise
Int
eine Klasse undint
ein Datentyp. Das Konvertierenint
inInt
ist ein Beispiel für Boxen, während das KonvertierenInt
inint
Unboxing ist. Das Konzept hilft bei der Speicherbereinigung, Unboxing hingegen konvertiert den Objekttyp in den Werttyp.quelle
var ii = 123; typeof ii
zurücknumber
.var iiObj = new Number(123); typeof iiObj
kehrt zurückobject
.typeof ii + iiObj
kehrt zurücknumber
. Das ist also das Javascript-Äquivalent zum Boxen. Der Wert iiObj wurde automatisch in eine primitive Zahl (ohne Box) konvertiert, um die Arithmetik durchzuführen und einen Wert ohne Box zurückzugeben.Wie alles andere kann Autoboxing problematisch sein, wenn es nicht sorgfältig verwendet wird. Der Klassiker besteht darin, eine NullPointerException zu erhalten und diese nicht aufzuspüren. Auch mit einem Debugger. Versuche dies:
quelle
i
wird vorzeitig initialisiert. Machen Sie es entweder zu einer leeren Deklaration (Integer i;
), damit der Compiler darauf hinweisen kann, dass Sie vergessen haben, es zu initialisieren, oder warten Sie, bis Sie den Wert kennen.