Warum verwenden wir Autoboxing und Unboxing in Java?

81

Autoboxing ist die automatische Konvertierung, die der Java-Compiler zwischen den primitiven Typen und den entsprechenden Objekt-Wrapper-Klassen vornimmt. Beispiel: Konvertieren eines int in eine Ganzzahl, eines Double in ein Double usw. Wenn die Konvertierung in die andere Richtung erfolgt, wird dies als Unboxing bezeichnet.

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

Theodoros Chatzigiannakis
quelle
1
Grundsätzlich für Generika ..
Nachokk
3
Integerhat parseIntMethode. inthat nicht. :)
Vishal Zanzrukia
@VishalZanzrukia Also nur um mehr Funktionalität zu bekommen?
11
Sie können haben List<Integer>, aber Sie können nicht haben List<int>.
Vishal Zanzrukia
Ja ... genau ... um mehr Funktionalität zu erhalten
Vishal Zanzrukia

Antworten:

173

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

Primitive versus Klassen

Primitive Variablen in Java enthalten Werte (eine Ganzzahl, eine Gleitkomma-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 (siehe floatversus double).

Andererseits enthalten Klassenvariablen Verweise auf Instanzen. Referenzen werden normalerweise in vielen Sprachen als Zeiger (oder ähnlich wie Zeiger) implementiert. Diese Dinge haben in der Regel die gleiche Größe, unabhängig von der Größe der Instanzen sie beziehen sich auf ( Object, String, Integer, usw.).

Diese Eigenschaft von Klassenvariablen macht die darin enthaltenen Referenzen (bis zu einem gewissen Grad) austauschbar . Dies ermöglicht es uns, das zu tun, was wir Substitution nennen : im Großen und Ganzen eine Instanz eines bestimmten Typs als Instanz eines anderen verwandten Typs zu verwenden ( z. B. a Stringals Object.

Primitive Variablen sind weder untereinander noch mit auf die gleiche Weise austauschbarObject . 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 Leistung hinauslaufen).

Generika und Typ Löschung

Generische Typen sind Typen mit einem oder mehreren Typparametern (die genaue Anzahl wird als generische Arität bezeichnet ). Beispielsweise verfügt die generische Typdefinition List<T> über einen Typparameter T, der Object(Erzeugen eines konkreten Typs List<Object> ), String( List<String>), Integer( List<Integer>) usw. sein kann.

Generische Typen sind viel komplizierter als nicht generische. Als sie (nach ihrer ersten Veröffentlichung) in Java eingeführt wurden, beschlossen die Entwickler von Java, generische Typen auf die am wenigsten invasive Weise zu implementieren , um radikale Änderungen an der JVM zu vermeiden und möglicherweise die Kompatibilität mit älteren Binärdateien zu beeinträchtigen: alle konkreten Typen von List<T>sind in der Tat kompiliert zu (dem binären Äquivalent von) List<Object>(für andere Typen kann die Grenze etwas anderes sein als Object, aber Sie bekommen den Punkt). Generische Aritäts- und Typparameterinformationen gehen bei diesem Prozess verloren , weshalb wir sie als Typlöschung bezeichnen .

Die beiden zusammenfügen

Das Problem ist jetzt die Kombination der oben genannten Realitäten: wenn List<T>wird List<Object>in allen Fällen, dann Tmuss immer ein Typ sein, der direkt zugeordnet werden kannObject . Alles andere kann nicht erlaubt werden. Da, wie schon gesagt, int, floatund doublemit nicht austauschbar sind Object, kann es keine sein List<int>, List<float>oder List<double>(es sei denn , eine wesentlich komplizierter Implementierung von Generika in der JVM existierte).

Aber Java jetzt Angebote mögen Integer, Floatund Doubledie diese Grundelemente in Klasseninstanzen wickeln, so dass sie effektiv substituierbar wie Object, so ermöglicht generische Typen , um indirekt die Arbeit mit der Primitiven als auch (weil Sie können haben List<Integer>, List<Float>, List<Double>und so weiter).

Das Erstellen eines Integeraus einem int, eines Floataus einem floatund so weiter wird als Boxen bezeichnet . Das Gegenteil heißt Unboxing . Da es Objectunpraktisch ist, Primitive jedes Mal zu boxen, wenn Sie sie verwenden möchten , gibt es Fälle, in denen die Sprache dies automatisch tut - das wird Autoboxing genannt .

Theodoros Chatzigiannakis
quelle
Gemäß Ihrer Erklärung benötigen wir diese Klassen Integer, String, ..., um Generika zu implementieren. Gibt es einen anderen Grund?
Bishwas Mishra
1
@BishwasMishra Wir haben sie, damit wir diese Werte als ObjectInstanzen verwenden können. Generika über Typlöschung sind eine Anwendung davon.
Theodoros Chatzigiannakis
16

Auto Boxing wird verwendet , um primitive Datentypen in ihre Wrapper-Klassenobjekte zu konvertieren. Die Wrapper-Klasse bietet einen breiten Funktionsumfang 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 Code direkt schreiben können und JVM sich um das Boxen und Unboxen kümmert.

Auto Boxing ist auch nützlich, wenn wir mit java.util.Collection-Typen arbeiten. Wenn wir eine Sammlung primitiver Typen erstellen möchten, können wir keine Sammlung eines primitiven Typs direkt erstellen, sondern nur eine Sammlung von Objekten. Zum Beispiel :

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

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

Wrapper-Klassen

Jedem der 8 primitiven Typen von Java (Byte, Short, Int, Float, Char, Double, Boolean, Long) ist eine separate Wrapper-Klasse zugeordnet. Diese Wrapper-Klassen verfügen über vordefinierte Methoden zum Ausführen nützlicher Operationen für primitive Datentypen.

Verwendung von Wrapper-Klassen

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

Es gibt viele nützliche Funktionen, die Wrapper-Klassen bieten. Schauen Sie sich hier die Java-Dokumente an

Unboxing ist das Gegenteil von Auto Boxing, bei dem das Wrapper-Klassenobjekt wieder in seinen primitiven Typ konvertiert wird. Dies wird automatisch von JVM durchgeführt, damit wir die Wrapper-Klassen für bestimmte Operationen verwenden und sie dann wieder in primitive Typen konvertieren können, da primitive Ergebnisse zu einer schnelleren Verarbeitung führen. Zum Beispiel :

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

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

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

int a = al.get(0); // returns the object of Integer . Automatically Unboxed . 
varun
quelle
4

Die primitiven (Nicht-Objekt-) Typen haben dort eine Rechtfertigung für die Effizienz.

Die primitiven Typen int, boolean, doublesind unmittelbare Daten, während Objects Referenzen sind. Daher Felder (oder Variablen)

int i;
double x;
Object s;

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

Unter Verwendung der Object-Wrapper Integer, Doubleund anderer würde eine Indirektion eingeführt, die auf eine Integer / Double-Instanz im Heap-Speicher verweist.

Warum wird Boxen benötigt?

Das ist eine Frage des relativen Umfangs. In einem zukünftigen Java ist geplant ArrayList<int>, primitive Typen zu heben.

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

Hier unterscheidet sich Java vom traditionellen C ++ mit seinen Vorlagen: C ++ - Klassen vector<string>, vector<int>würden zwei Kompilierungsprodukte erstellen. Beim Java-Design wurde eine ArrayList.class verwendet, und nicht für jeden Parametertyp wurde ein neues kompiliertes Produkt benötigt.

Ohne Boxing to Object müsste man also Klassen für jedes Auftreten eines Parametertyps kompilieren. In concreto: Jede Sammlung oder Containerklasse würde eine Version für Object, int, double, boolean benötigen. Die Version für Object würde alle untergeordneten Klassen behandeln.

Tatsächlich bestand in Java SE bereits die Notwendigkeit einer solchen Diversifizierung für IntBuffer, CharBuffer, DoubleBuffer, ..., die mit int, char, double arbeiten. Es wurde auf hackige Weise gelöst, indem diese Quellen aus einer gemeinsamen Quelle generiert wurden .

Joop Eggen
quelle
4

Ab JDK 5 hat Java zwei wichtige Funktionen hinzugefügt: Autoboxing und Autounboxing. AutoBoxing ist der Prozess, für den ein primitiver Typ automatisch in den entsprechenden Wrapper gekapselt wird, wenn ein solches Objekt benötigt wird. Sie müssen kein Objekt explizit erstellen. Auto-Unboxing ist der Prozess, bei dem der Wert eines gekapselten Objekts automatisch aus einem Typ-Wrapper extrahiert wird, wenn sein Wert benötigt wird. Sie müssen keine Methode wie intValue () oder doubleValue () aufrufen .

Das Hinzufügen von Autoboxing und Auto-Unboxing vereinfacht das Schreiben von Algorithmen erheblich und eliminiert das manuelle Ein- und Auspacken von Werten. Es ist auch hilfreich, Fehler zu vermeiden . Dies ist auch sehr wichtig für Generika , die nur Objekte bearbeiten. Schließlich erleichtert Autoboxing die Arbeit mit dem Collections Framework .

Amarildo
quelle
2

Warum haben wir (Un) Boxen?

um das Schreiben von Code, in dem wir Grundelemente und ihre objektorientierten (OO) Alternativen mischen, komfortabler / weniger ausführlich zu gestalten.

Warum haben wir Primitive und ihre OO-Alternativen?

Primitive Typen sind keine Klassen (im Gegensatz zu C #), daher sind sie keine Unterklassen von Objectund können nicht überschrieben werden.

Wir haben Grundelemente wie intaus Leistungsgründen und ObjectAlternativen wie Integerfür die Vorteile der OO-Programmierung und als kleinen Punkt, um einen guten Speicherort für Dienstprogrammkonstanten und -methoden (Integer.MAX_VALUE und Integer.toString(int)) zu haben.

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

Number getMeSome(boolean wantInt) {

    if (wantInt) {
        return Integer.MAX_VALUE;
    } else {
        return Long.MAX_VALUE;
    }
}
hoijui
quelle
0

Weil es sich um verschiedene Typen handelt und aus praktischen Gründen. Leistung ist wahrscheinlich der Grund für primitive Typen.

Scott Hunter
quelle
0

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

Beispiel: Der Schlüssel in einer HashMap.

Weitere Informationen finden Sie in dieser Frage: HashMap und int als Schlüssel

Es gibt andere gute Gründe, z. B. ein "int" -Feld in einer Datenbank, das ebenfalls NULL sein kann. Ein int in Java kann nicht null sein. eine Integer-Referenz kann. Autoboxing und Unboxing bieten die Möglichkeit, das Schreiben von Fremdcode in die Konvertierungen hin und her zu vermeiden.

Gabriel
quelle
0

ArrayList unterstützt nicht nur primitive Typen, sondern auch Klassen. aber wir müssen primitive Typen verwenden, z. B. int, double usw.

ArrayList<String> strArrayList = new ArrayList<String>(); // is accepted.

ArrayList<int> intArrayList = new ArrayList<int>(); // not accepted.

Die Integer-Klasse umschließt einen Wert vom primitiven Typ int in einem Objekt. Daher wird der folgende Code akzeptiert.

ArrayList<Integer> intArrayList = new ArrayList<Integer>(); // is accepted.

Wir können einen Wert mit der Methode add (value) hinzufügen. Um einen String-Wert hinzuzufügen, sagen Sie "Hallo" im strArrayList-Code

strArrayList.add("Hello");  

und füge einen int-Wert hinzu, sagen wir 54, wir können schreiben

intArrayList.add(54);

aber wenn wir intArrayList.add (54) schreiben; Compiler konvertieren in die folgende Zeile

intArrayList.add(Integer.valueOf(54)); 

Da intArrayList.add (54) auf Benutzerseite einfach und akzeptabler ist, erledigt der Compiler die harte Arbeit, nämlich " intArrayList.add(Integer.valueOf(54));es ist AutoBoxing".

In ähnlicher Weise geben wir zum Abrufen des Werts einfach intArrayList.get (0) und die Compilerkonvertierung ein, in <code>intArrayList.get(0).intValue();die autoUnboxing ausgeführt wird.

Chhalma Sultana Chhaya
quelle
0

Autoboxing: Konvertieren eines primitiven Werts in ein Objekt der entsprechenden Wrapper-Klasse.

Unboxing: Konvertieren eines Objekts eines Wrapper-Typs in den entsprechenden Grundwert

// Java program to illustrate the concept 
// of Autoboxing and Unboxing 
import java.io.*; 

class GFG 
{ 
    public static void main (String[] args) 
    { 
        // creating an Integer Object 
        // with value 10. 
        Integer i = new Integer(10); 

        // unboxing the Object 
        int i1 = i; 

        System.out.println("Value of i: " + i); 
        System.out.println("Value of i1: " + i1); 

        //Autoboxing of char 
        Character gfg = 'a'; 

        // Auto-unboxing of Character 
        char ch = gfg; 
        System.out.println("Value of ch: " + ch); 
        System.out.println("Value of gfg: " + gfg); 

    } 
} 
Yash Patel
quelle