Heim  >  Artikel  >  Java  >  Zusammenfassung der fehlertoleranten Behandlung von Nullobjekten durch Java String

Zusammenfassung der fehlertoleranten Behandlung von Nullobjekten durch Java String

黄舟
黄舟Original
2017-03-31 11:07:061540Durchsuche

Vorwort

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.

Der Prozess der Lösung des Problems

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.

Die erste Frage

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.

Die zweite Frage

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.

  1. String-Objekt : Bestimmen Sie direkt, ob es null ist. Wenn es null ist, weisen Sie dem Nullobjekt den Wert als "null" zu.

  2. 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.

Die dritte Frage (verstecktes Fest)

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++] = &#39;n&#39;;
    value[c++] = &#39;u&#39;;
    value[c++] = &#39;l&#39;;
    value[c++] = &#39;l&#39;;
    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.

Zusammenfassung

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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn