In diesem Artikel wird der Autor Ihnen ein sehr wichtiges und interessantes Feature in Java vorstellen, bei dem es sich um automatische Boxen und Unboxen handelt, und die Prinzipien des automatischen Boxens und Unboxens aus dem Quellcode interpretiert. Gleichzeitig hinterlässt diese Funktion auch eine Falle. Wenn Entwickler nicht aufpassen, werden sie leicht in diese Falle fallen.
Autoboxen
Definition
Beim Schreiben von Java -Programmen definieren Menschen ein ganzzahliges Objekt häufig auf folgende Weise:
Ganzzahl i = 100;
Aus dem obigen Code können Sie wissen, dass ich eine Referenz von Typ Ganzeer ist und 100 der grundlegende Datentyp in Java (primitiver Datentyp) ist. Diese Methode zum direkten Übergeben eines grundlegenden Datentyps an seine entsprechende Wrapper -Klasse ist das automatische Boxen.
In JDK 1.5 wurde zum ersten Mal automatisches Boxen eingeführt. Wenn Sie vor JDK 1.5 ein ganzzahliges Objekt mit einem Wert von 100 definieren möchten, müssen Sie dies tun:
Ganzzahl I = New Integer (100);
Prinzip
Lassen Sie uns einen Haltepunkt am obigen Code "Ganzzahl i = 100" erstellen; und folge ihm.
Als nächstes können wir sehen, dass das Programm zur ValueOF (int i) -Methode der Ganzzahlklasse springt.
/** * Gibt eine <Tt> Integer </tt> Instanz zurück, die den angegebenen * <tt> int </tt> Wert darstellt. * Wenn keine neue <Tt> Integer </tt> Instanz erforderlich ist, sollte diese Methode * im Allgemeinen für den Konstruktor verwendet werden * * @param i an <code> int </code> Wert. * @return a <tt> Integer </tt> Instanz, die <tt> i </tt> darstellt. * @Since 1.5 */ public static Integer ValueOf (int i) {if (i> = -128 && i <= IntegerCache.High) return IntegerCache.cache [i + 128]; sonst kehren Sie eine neue Integer zurück (i); }Mit anderen Worten, Packing ist JDK, mit dem Sie den Anruf nach Integer.Valueof (100) abschließen können.
Unboxing
Definition
Integer Integer100 = 100; int100 = Integer100;
Aus dem obigen Code können Sie sehen, dass Integer100 ein Verweis auf Typ Ganzeer ist und INT100 ein primitiver Datentyp vom Typ int ist. Wir können jedoch einer Variablen seines entsprechenden Originaldatentyps ein ganzzahliges Objekt zuweisen. Dies ist Unboxing.
Unboxing ist das Gegenteil von Packungen. Das Boxen ist eine Variable, die der entsprechenden eingekapselten Klasse einen primitiven Datentyp zuweist. Unboxing bedeutet, eine Variable einer eingekapselten Klasse einer Variablen des entsprechenden Original -Datentyps zugewiesen zu werden. Auch die Namen des Packens und des Unboxing sind sehr angemessen.
Prinzip
Ich glaube, jeder hat vermutet, was JDK während des Unboxing -Prozesses für uns getan hat. Lassen Sie uns unsere Vermutung durch Experimente beweisen.
Legen Sie einen Haltepunkt in der zweiten Zeile des obigen Codes fest, dh einen Haltepunkt auf "int100 = Integer100"; und folge ihm.
Wir können sehen, dass das Programm zur IntValue () -Methode von Integer springt.
/** * Gibt den Wert dieses <code> Integer </code> als * <Code> int </code> zurück. */ public intValue () {Rückgabewert; }Das heißt, JDK hilft uns, den Anruf bei der Intvalue () -Methode zu vervollständigen. Für das obige Experiment soll die IntValue () -Methode von Integer100 aufgerufen werden und ihren Rückgabewert INT100 zuweisen.
Erweitert
Experiment 1
Integer Integer400 = 400; int400 = 400; System.out.println (Integer400 == INT400);
In der dritten Zeile des obigen Codes führen Integer400 und INT400 den == Run aus. Und diese beiden sind verschiedene Arten von Variablen. Sind Integer400 Unboxing oder INT400 Packung? Was sind die Ergebnisse der Operation?
== Die Operation besteht Daher ist es leicht zu schließen, dass, wenn INTEGER400 nicht mehr enttroffen ist, dies bedeutet, dass die Werte der beiden Grundtypen verglichen werden und das laufende Ergebnis zu diesem Zeitpunkt wahr sein muss. Wenn INT400 gepackt ist, bedeutet dies, dass die Adressen der beiden Objekte gleich sind und das laufende Ergebnis zu diesem Zeitpunkt falsch sein muss. (Was der Grundlage des Autors an 400 zuweist, bezieht sich auf die Fallen, die später erörtert werden.)
Unser tatsächliches laufendes Ergebnis ist wahr. Es war also Integer400 Unboxing. Die Ergebnisse der Codeverfolgung beweisen dies.
Experiment 2
Integer Integer100 = 100; int100 = 100; System.out.println (Integer100.Equals (int100));
In der dritten Zeile des obigen Codes beträgt der Parameter der Methode von Integer100 int100. Wir wissen, dass die Parameter der Equals -Methode Objekt sind, nicht der grundlegende Datentyp. Hier muss es int100 gepackt sein. Die Ergebnisse der Codeverfolgung beweisen dies.
Wenn der Parametertyp in einer Methode der ursprüngliche Datentyp ist und der in die in die Kapselungsklasse übergebene Parametertyp ist automatisch nicht geplant. Wenn der Parametertyp in einer Methode der Kapselungstyp ist und der in in das übergebene Parametertyp sein ursprünglicher Datentyp ist, wird er automatisch eingewendet.
Experiment 3
Integer Integer100 = 100; int100 = 100; long200 = 200l; System.out.println (Integer100 + int100); System.out.println (long200 == (Integer100 + int100);
Im ersten Experiment haben wir gelernt, dass die Kapselungsklasse, wenn ein Basistyp mit der Einkapselungsklasse mit der Einkapselungsklasse ausgeführt wird. Was ist, wenn +, -, *, /? Wir können in diesem Experiment wissen.
Wenn + Betriebsbetrieb, wird der zugrunde liegende Datentyp unterbacken, dann:
• In Zeile 4 erhält Integer100+int100 ein Objekt O -Typ Ganzzahl und Wert 200 und führt die Methode für toString () dieses Objekts und die Ausgabe "200" aus.
• In Zeile 5 erhält Integer100+INT100 ein Objekt O Ganzzahl und Wert von 200. Die == Operation vergleicht dieses Objekt mit einem Long200 -Objekt. Offensichtlich wird falsch ausgegeben;
• In Zeile 6 erhält Integer100+int100 ein Objekt O von Typ Ganze und Wert 200. Long's Equals -Methode vergleicht Long200 mit O, da beide eingekapselten Klassen verschiedener Typen sind, sodass der Ausgang falsch ist.
Wenn + Operation, wird die Kapselungsklasse nicht enttäuscht, dann:
• In Zeile 4 erhält Integer100+INT100 einen grundlegenden Datentyp B des Typs in int und des Werts 200, dann ein Kasten B, um O zu erhalten, die Methode toString () dieses Objekts auszuführen und "200" auszugeben.
• In Zeile 5 erhält Integer100+INT100 einen grundlegenden Datentyp B1 vom Typ int und Wert 200. Die == Operation Unboxes long200, um B2 zu erhalten. Offensichtlich B1 == B2 und gibt wahr aus;
• In Zeile 6 erhält Integer100+INT100 einen grundlegenden Datentyp B vom Typ Int und Value 200. Long's Equals -Methodenboxs B, aber das Boxing führt zu Objekt O von Typ Integer, da O und Long200 Objekte verschiedener Typen sind, sodass die Ausgabe falsch ist.
Das Ergebnis des Programms ist:
200
WAHR
FALSCH
Daher ist die zweite Spekulation korrekt, dh die Einkapselungsklasse wird während der + Operation enttäuscht.
fangen
Falle 1
Integer Integer100 = null;
INT INT100 = INTEGER100;
Diese beiden Codezeilen sind völlig legal und können vollständig zusammengestellt werden. Wenn jedoch ausgeführt wird, wird eine Null -Zeiger -Ausnahme ausgelöst. Unter diesen ist Integer100 ein Objekt des Typ -Ganzzins, das natürlich auf NULL verweisen kann. In der zweiten Zeile wird Integer100 jedoch nicht mehr enttäuscht, dh die Methode intValue () wird auf einem Null -Objekt ausgeführt, und natürlich wird eine Null -Zeiger -Ausnahme ausgeworfen. Daher müssen Sie beim Entbinden besonders darauf achten, ob das eingekapselte Klassenobjekt null ist.
Falle 2
Ganzzahl i1 = 100;
Ganzzahl i2 = 100;
Ganzzahl i3 = 300;
Ganzzahl i4 = 300;
System.out.println (i1 == i2);
System.out.println (i3 == i4);
Weil I1, I2, I3 und I4 alle ganzzahligen Typen sind, denken wir, dass die laufenden Ergebnisse falsch sein sollten. Das reale laufende Ergebnis ist jedoch "System.out.println (i1 == i2);" Das ist wahr, aber "System.out.println (i3 == i4);" Welches ist falsch. Dies bedeutet, dass die Referenzen der beiden Ganzzahltypen I1 und I2 auf dasselbe Objekt verweisen, während I3 und I4 auf verschiedene Objekte hinweisen. Warum? Sind sie nicht alle die Integer.Valueof (int i) -Methode genannt?
Werfen wir einen Blick auf die Integer.Valueof (int i) -Methode.
/** * Gibt eine <Tt> Integer </tt> Instanz zurück, die den angegebenen * <tt> int </tt> Wert darstellt. * Wenn keine neue <Tt> Integer </tt> Instanz erforderlich ist, sollte diese Methode * im Allgemeinen für den Konstruktor verwendet werden * * @param i an <code> int </code> Wert. * @return a <tt> Integer </tt> Instanz, die <tt> i </tt> darstellt. * @Since 1.5 */ public static Integer ValueOf (int i) {if (i> = -128 && i <= IntegerCache.High) return IntegerCache.cache [i + 128]; sonst kehren Sie eine neue Integer zurück (i); }Wir können sehen, dass der IntegerCache.cache [i + 128] direkt zurückgegeben wird, wenn i> =-128 und i <= Integercache.High.HIGHT direkt zurückgegeben werden. Unter ihnen ist IntegerCache eine interne statische Klasse von Ganzzahl, und sein ursprünglicher Code lautet wie folgt:
private statische Klasse IntegerCache {statische endgültige int hoch; statischer endgültiger Ganzzahl -Cache []; static {endgültig int low = -128; // hoher Wert kann durch Eigenschaft int H = 127 konfiguriert werden; if (IntegerCacheHighPropValue! i = math.max (i, 127); // Maximale Arraygröße ist integer.max_value h = math.min (i, integer.max_value - -low); } High = H; Cache = New Integer [(hoch - niedrig) + 1]; int j = niedrig; für (int k = 0; k <cache.length; k ++) cache [k] = new Integer (j ++); } private IntegerCache () {}}Wir können deutlich sehen, dass IntegerCache einen statischen Mitgliedsvariablen -Cache hat, bei dem es sich um ein Array mit 256 Elementen handelt. Der Cache wird auch in IntegerCache initialisiert, dh das I-te-Element ist ein ganzzahliges Objekt mit einem Wert von I-128. -128 bis 127 sind die am häufigsten verwendeten Ganzzahlobjekte, und dieser Ansatz verbessert auch die Leistung erheblich. Aus diesem Grund erhalten "Integeri1 = 100; Integer i2 = 100;", I1 und I2 das gleiche Objekt.
Wenn wir das zweite Experiment in der Erweiterung vergleichen, haben wir erfunden, dass die Kapselungsklasse, wenn die Kapselungsklasse ausgeführt wird, mit dem Basistyp läuft, und das Unboxing -Ergebnis wird mit dem Basistyp verglichen. Wenn die beiden Kapselungsklassen mit den anderen Objekten ausgeführt werden, vergleichen sie die Adressen der beiden Objekte, dh, um zu bestimmen, ob die beiden Referenzen auf dasselbe Objekt hinweisen.
In dem obigen Artikel werden die automatischen Packungen und Unboxen von Java kurz erläutert und seine Fallen sind der Inhalt, den ich mit Ihnen teile. Ich hoffe, es kann Ihnen eine Referenz geben und ich hoffe, Sie können Wulin.com mehr unterstützen.