Warum verwenden wir Autoboxing und Unboxing in Java?

Autoboxing ist die automatische Konvertierung, die der Java-Compiler zwischen den primitiven Typen und ihren entsprechenden Wrapper-Objektklassen vornimmt. Konvertieren Sie beispielsweise ein int in ein Integer, ein double in ein Double und so weiter. Wenn die Konvertierung in die andere Richtung geht, wird dies als Unboxing bezeichnet.

Warum brauchen wir es und warum verwenden wir Autoboxing und Unboxing in Java?

   

Ein gewisser Kontext ist erforderlich, um den Hauptgrund dafür vollständig zu verstehen.

Primitive versus classn

Primitive Variablen in Java enthalten Werte (eine Ganzzahl, eine Fließkomma-Binärzahl mit doppelter Genauigkeit usw.). Da diese Werte unterschiedliche Längen haben können , können die Variablen, die sie enthalten, auch unterschiedliche Längen haben (berücksichtigen Sie float versus double ).

Auf der anderen Seite enthalten classnvariablen Verweise auf Instanzen. Verweise werden in der Regel als pointers (oder als pointers) in vielen Sprachen implementiert. Diese Dinge haben normalerweise die gleiche Größe, unabhängig von der Größe der Instanzen, auf die sie verweisen ( Object , String , Integer usw.).

Diese Eigenschaft der classnvariablen macht die darin enthaltenen Referenzen (in gewissem scope) austauschbar . Dies ermöglicht es uns, etwas zu tun, was wir Substitution nennen: eine Instanz eines bestimmten Typs als Instanz eines anderen verwandten Typs zu verwenden (z. B. einen String als ein Object zu verwenden).

Primitive Variablen sind nicht auf die gleiche Weise austauschbar , weder untereinander noch mit dem Object . Der offensichtlichste Grund dafür (aber nicht der einzige Grund) ist ihr Größenunterschied. Dies macht primitive Typen in dieser Hinsicht unpraktisch, aber wir brauchen sie immer noch in der Sprache (aus Gründen, die hauptsächlich auf die performance hinauslaufen).

Generika und Typ löschen

Generische Typen sind Typen mit einem oder mehreren Typparametern (die genaue Nummer wird generische Arität genannt ). Zum Beispiel hat die generische Typdefinition List einen Typparameter T , der Object (erzeugt einen konkreten Typ List ), String ( List ), Integer ( List ) und so weiter .

Generische Typen sind viel komplizierter als nicht-generische Typen. Als sie nach ihrer Einführung in Java eingeführt wurden, um radikale Änderungen an der JVM zu vermeiden und möglicherweise die Kompatibilität mit älteren Binärdateien zu brechen, entschieden sich die Entwickler von Java dafür, generische Typen auf die am wenigsten invasive Art zu implementieren: alle konkreten Arten von List wird tatsächlich zu (der binären Entsprechung von) List kompiliert (für andere Typen kann die Grenze etwas anderes als Object , aber Sie erhalten den Punkt). Generische arity- und type-Parameter-Informationen gehen bei diesem process verloren , weshalb wir es als Type-Löschung bezeichnen .

Putting die zwei zusammen

Jetzt ist das Problem die Kombination der obigen Realitäten: wenn List in allen Fällen zu List wird, dann muss T immer ein Typ sein, der direkt Object zugewiesen werden kann . Alles andere kann nicht erlaubt sein. Da, wie bereits erwähnt, int , float und double nicht mit Object austauschbar sind, kann es keine List , List oder List (sofern nicht eine wesentlich kompliziertere Implementierung von Generics existiert) die JVM).

Aber Java bietet Typen wie Integer , Float und Double die diese Primitive in classninstanzen einbinden und sie so effektiv als Object substituierbar machen, sodass generische Typen indirekt auch mit den Primitiven arbeiten können (weil Sie List , List , List und so weiter).

Der process zum Erstellen einer Integer aus einem int , einem Float aus einem float und so weiter, wird Boxen genannt . Das Umgekehrte heißt Unboxing . Da es jedes Mal, wenn Sie Object als Object möchten, erforderlich ist, primitive Object einzuschließen, gibt es Fälle, in denen die Sprache dies automatisch tut – das wird Autoboxing genannt .

Auto Boxing wird verwendet , um primitive Datentypen in ihre Wrapper-classnobjekte zu konvertieren. Die Wrapper-class bietet einen großen functionsumfang für die primitiven Typen. Das häufigste Beispiel ist:

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

Es wird benötigt, weil Programmierer einfach in der Lage sind, Code direkt zu schreiben und JVM kümmert sich um das Boxen und Unboxing.

Auto-Boxen ist auch praktisch, wenn wir mit java.util.Collection-Typen arbeiten. Wenn wir eine Sammlung primitiver Typen erstellen wollen, können wir nicht direkt eine Sammlung eines primitiven Typs erstellen, sondern nur die Sammlung von Objekten. Beispielsweise :

 ArrayList al = new ArrayList(); // not supported ArrayList al = new ArrayList(); // supported al.add(45); //auto Boxing 

Wrapper-classn

Jeder der primitiven Java-Typen 8 (byte, short, int, float, char, double, boolean, long) hat eine separate Wrapper-class, die mit ihnen verbunden ist. Diese Wrapper-class verfügt über vordefinierte Methoden zum Vorbereiten nützlicher Operationen für primitive Datentypen.

Verwendung von Wrapper-classn

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

Es gibt viele nützliche functionen, die Wrapper-classn bieten. Schau dir die Java-Dokumente hier an

Unboxing ist das Gegenteil von Auto Boxing, wo wir das Wrapper-classnobjekt zurück in seinen primitiven Typ konvertieren. Dies geschieht automatisch durch JVM, so dass wir die Wrapper-classn für bestimmte Operationen verwenden und sie dann in primitive Typen zurück konvertieren können, da Primitive eine schnellere Verarbeitung zur Folge haben. Beispielsweise :

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

Bei Sammlungen, die mit Objekten arbeiten, wird nur das automatische Entpacken verwendet. Hier ist wie :

 ArrayList al = new ArrayList(); al.add(45); int a = al.get(0); // returns the object of Integer . Automatically Unboxed . 

Die primitiven (Nicht-Objekt-) Typen haben ihre Berechtigung in der Effizienz.

Die primitiven Typen int, boolean, double sind unmittelbare Daten, während Object s Verweise sind. Also Felder (oder Variablen)

 int i; double x; Object s; 

würde lokalen Speicher 4 + 8 + 8 benötigen? wo für das Objekt nur die Referenz (Adresse) zum Speicher gespeichert wird.

Mit den Objektwrappern Integer, Double und anderen würde man eine Indirektion, einen Verweis auf eine Integer / Double-Instanz im Heap-Speicher einführen.

Warum Boxen benötigt wird?

Das ist eine Frage des relativen scopes. In einem zukünftigen Java ist geplant, eine ArrayList , die primitive Typen ArrayList .

Antwort: Momentan funktioniert eine ArrayList nur für Objekt, reserviert Platz für eine Objektreferenz und verwaltet Garbage Collection ebenfalls. Daher sind generische Typen Objektkinder. Wenn man also eine ArrayList mit Fließkommawerten wollte, musste man ein Double in ein Double-Objekt einschließen.

Hier unterscheidet sich Java von dem traditionellen C ++ mit seinen Templates: C ++ classn vector, vector würde zwei Kompilierungsprodukte erzeugen. Beim Java-Design wurde eine ArrayList.class verwendet, die nicht für jeden Parametertyp ein neues kompiliertes Produkt benötigt.

Also ohne Boxen zu Objekt müsste man classn für jedes Auftreten eines Parametertyps kompilieren. Konkret: Jede Sammlung oder Container-class würde eine Version für Object, int, double und boolean benötigen. Die Version für Object würde alle untergeordneten classn behandeln.

Die Notwendigkeit einer solchen Diversifizierung bestand bereits in Java SE für IntBuffer, CharBuffer, DoubleBuffer, …, die mit int, char, double arbeiten. Es wurde auf hacky Weise getriggers, indem diese Quellen aus einem gemeinsamen erzeugt wurden.

Ab JDK 5 hat Java zwei wichtige functionen hinzugefügt: Autoboxing und Auto-Boxing. AutoBoxing ist der process, bei dem ein primitiver Typ automatisch in den äquivalenten Wrapper eingekapselt wird, wenn ein solches Objekt benötigt wird. Sie müssen ein Objekt nicht explizit konstruieren. Auto-Unboxing ist der process, bei dem der Wert eines gekapselten Objekts automatisch aus einem Typ-Wrapper extrahiert wird, wenn sein Wert erforderlich ist. Sie müssen keine Methode wie intValue () oder doubleValue () aufrufen .

Das Hinzufügen von Autoboxing und Auto-Unboxing vereinfacht Schreibalgorithmen erheblich und eliminiert den Köder beim manuellen Boxen und Entpacken von Werten. Es ist auch hilfreich, Fehler zu vermeiden . Es ist auch sehr wichtig für Generika , die nur an Objekten arbeiten. Schließlich erleichtert Autoboxing die Arbeit mit dem Collections Framework .

Warum haben wir (un) boxen?

um Code zu schreiben, wo wir Primitive und ihre Objektorientierten (OO) Alternativen komfortabler / weniger ausführlich mischen.

Warum haben wir Primitive und ihre OO-Alternativen?

primitive Typen sind keine classn (anders als in C #), daher sind sie keine Unterklassen von Object und können nicht überschrieben werden.

Wir haben Primitive wie int aus Gründen der Performance und die Object Alternativen wie Integer für die Vorteile der OO-Programmierung und als Nebensatz, um eine gute Position für Utility-Konstanten und Methoden zu haben (Integer.MAX_VALUE und Integer.toString(int) ) .

Die OO-Vorteile sind am einfachsten mit Generics sichtbar ( List ), sind aber nicht darauf beschränkt, zum Beispiel:

 Number getMeSome(boolean wantInt) { if (wantInt) { return Integer.MAX_VALUE; } else { return Long.MAX_VALUE; } } 

Weil sie verschiedene Arten sind, und als Bequemlichkeit. performance ist wahrscheinlich der Grund für primitive Typen.

Einige Datenstrukturen können nur Objekte, keine primitiven Typen akzeptieren.

Beispiel: Der Schlüssel in einer HashMap.

Siehe diese Frage für mehr: HashMap und int als Schlüssel

Es gibt andere gute Gründe, wie zum Beispiel ein “int” -Feld in einer database, das auch NULL sein könnte. Ein int in Java darf nicht null sein; eine Integer-Referenz kann. Autoboxing und Unboxing bieten die Möglichkeit, überflüssigen Code in den Conversions hin und her zu schreiben.