Ich habe kürzlich „Thinking in Java“ gelesen und diese Passage gesehen:
Primitive, die Felder in einer Klasse sind, werden automatisch auf Null initialisiert, wie im angegeben Aber die Objektreferenzen werden auf Null initialisiert, und wenn Sie versuchen, Methoden für eine davon aufzurufen, erhalten Sie eine Ausnahme – einen Laufzeitfehler. Praktischerweise können Sie trotzdem eine Nullreferenz ausgeben, ohne eine auszulösen Ausnahme.
Die Hauptidee ist: Der native Typ wird automatisch auf 0 initialisiert, aber die Objektreferenz wird auf null initialisiert. Wenn Sie versuchen, die Methode des Objekts aufzurufen, wird eine Nullzeigerausnahme ausgelöst. Normalerweise können Sie ein Nullobjekt drucken, ohne eine Ausnahme auszulösen.
Ich glaube, der erste Satz wird für jeden leicht zu verstehen sein. Dies ist das Grundwissen der Typinitialisierung, aber der zweite Satz verwirrt mich: Warum löst das Drucken eines Nullobjekts keine Ausnahme aus? Mit dieser Frage im Hinterkopf begann ich meine Reise des Verstehens. Im Folgenden werde ich meine Ideen zur Lösung dieses Problems näher erläutern und mich im JDK-Quellcode umsehen, um die Antwort auf das Problem zu finden.
Es kann festgestellt werden, dass es tatsächlich mehrere Situationen für dieses Problem gibt, daher werden wir verschiedene Situationen in Kategorien diskutieren, um zu sehen, ob wir die Antwort darin finden können Ende.
Zuerst zerlegen wir dieses Problem in drei kleine Probleme und lösen sie nacheinander.
Welches Ergebnis erhalten Sie, wenn Sie ein Null-String-Objekt direkt drucken? Das Ergebnis der Ausführung von
String s = null; System.out.print(s);
ist
null
. Wie das Buch sagt, wird keine Ausnahme ausgelöst, aber null
wird gedruckt. Offensichtlich liegt der Hinweis auf das Problem im Quellcode der Funktion print
. Wir haben den Quellcode von print
gefunden:
public void print(String s) { if (s == null) { s = "null"; } write(s); }
Als ich den Quellcode sah, wurde mir klar, dass es sich nur um ein einfaches und grobes Urteil handelte Implementierung von JDK. Keine Sorge, die erste Frage ist nur eine Vorspeise, das Fest steht noch bevor.
Drucken Sie ein Null-Nicht-String-Objekt, zum Beispiel Integer:
Integer i = null; System.out.print(i);
Das Ergebnis der Operation ist nicht überraschend:
null
Werfen wir einen Blick auf den Quellcode von print
:
public void print(Object obj) { write(String.valueOf(obj)); }
ist etwas anders. Es scheint, dass das Geheimnis in valueOf
verborgen ist.
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }
Als wir das sahen, entdeckten wir endlich das Geheimnis, Nullobjekte zu drucken, ohne Ausnahmen auszulösen. Die print
-Methode behandelt String-Objekte und Nicht-String-Objekte getrennt.
String-Objekt : Bestimmen Sie direkt, ob es null ist. Wenn es null ist, weisen Sie dem Nullobjekt den Wert als "null"
zu.
Nicht-String-Objekt : Wenn es sich um ein Nullobjekt handelt, geben Sie durch Aufrufen der String.valueOf
-Methode "null"
zurück, andernfalls rufen Sie das toString
des Objekts auf Verfahren.
Durch die obige Verarbeitung kann garantiert werden, dass das Drucken von Nullobjekten keine Fehler verursacht.
Hier sollte dieser Artikel enden.
Was? Wo ist das versprochene Abendessen? Es reicht nicht aus, um zwischen die Zähne zu passen.
Nur ein Scherz. Lassen Sie uns die dritte Frage unten untersuchen.
Was wird das Ergebnis der Verkettung von Nullobjekt und Zeichenfolge sein?
String s = null; s = s + "!"; System.out.print(s);
Sie haben vielleicht das Ergebnis erraten:
null!
Warum? Das Verfolgen der Codeausführung zeigt, dass es dieses Mal nichts mit print
zu tun hat. Aber der obige Code ruft die Funktion print
auf, wer könnte es sonst sein? +
ist am verdächtigsten, aber +
ist keine Funktion. Wie können wir den Quellcode sehen? In diesem Fall besteht die einzige Erklärung darin, dass der Compiler den Quellcode manipuliert hat. Wir können uns den vom Compiler generierten Bytecode ansehen.
L0 LINENUMBER 27 L0 ACONST_NULL ASTORE 1 L1 LINENUMBER 28 L1 NEW java/lang/StringBuilder DUP INVOKESPECIAL java/lang/StringBuilder.<init> ()V ALOAD 1 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; LDC "!" INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; ASTORE 1 L2 LINENUMBER 29 L2 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; ALOAD 1 INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/String;)V
Sind Sie verwirrt, nachdem Sie den obigen Bytecode gelesen haben? Hier werden wir das Thema wechseln und über +
das Prinzip des String-Spleißens sprechen.
Der Compiler optimiert zunächst ein StringBuilder
, bringt dann die hinzugefügten Zeichenfolgen in die richtige Reihenfolge append
und ruft schließlich toString
auf, um ein String
-Objekt zurückzugeben. Wenn Sie mir nicht glauben, schauen Sie sich den Bytecode oben an, um zu sehen, ob StringBuilder
erscheint. Eine ausführliche Erklärung finden Sie in diesem Artikel „Java-Details: String-Spleißen“.
String s = "a" + "b"; //等价于 StringBuilder sb = new StringBuilder(); sb.append("a"); sb.append("b"); String s = sb.toString();
Zurück zu unserem Problem: Jetzt wissen wir, dass das Geheimnis im Quellcode der Funktion StringBuilder.append
liegt.
//针对 String 对象 public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; } //针对非 String 对象 public AbstractStringBuilder append(Object obj) { return append(String.valueOf(obj)); } private AbstractStringBuilder appendNull() { int c = count; ensureCapacityInternal(c + 4); final char[] value = this.value; value[c++] = 'n'; value[c++] = 'u'; value[c++] = 'l'; value[c++] = 'l'; count = c; return this; }
Jetzt stellen wir plötzlich fest, dass die Funktion append
, wenn sie feststellt, dass das Objekt null ist, appendNull
aufruft und "null"
ausfüllt.
Wir haben oben drei Probleme besprochen, die zur fehlertoleranten Behandlung von String-Null-Objekten in Java führen. Das obige Beispiel deckt nicht alle Verarbeitungssituationen ab und dient als Einführung.
Wie wir das Nullobjekt im Programm unter unserer Kontrolle halten, ist etwas, worauf wir beim Programmieren immer achten müssen.
Das obige ist der detaillierte Inhalt vonZusammenfassung der fehlertoleranten Behandlung von Nullobjekten durch Java String. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!