Wenn Sie eine Referenzvariable (d. h. ein Objekt) deklarieren, erstellen Sie einen Zeiger auf ein Objekt. Betrachten Sie den folgenden Code, in dem Sie eine Variable vom primitiven Typ int
deklarieren:
In diesem Beispiel ist die Variable x ein int
und Java initialisiert es für Sie auf 0. Wenn Sie es in der zweiten Zeile auf 10 setzen, wird Ihr Wert 10 in den Speicherplatz geschrieben, auf den x zeigt.
Aber wenn Sie versuchen, einen Referenztyp zu deklarieren, passiert etwas anderes. Nimm den folgenden Code:
%Vor% Die erste Zeile deklariert eine Variable mit dem Namen num
, aber sie enthält keinen primitiven Wert. Stattdessen enthält es einen Zeiger (weil der Typ Integer
ist, was ein Referenztyp ist). Da Sie noch nicht gesagt haben, was Sie auf Java zeigen sollen, setzen Sie es auf null, was bedeutet " Ich zeige auf nichts ".
In der zweiten Zeile wird das Schlüsselwort new
verwendet, um ein Objekt vom Typ Integer zu instanziieren (oder zu erstellen), und der Zeigervariable num
wird dieses Objekt zugewiesen. Sie können nun mit dem Dereferenzierungsoperator .
(ein Punkt) auf das Objekt verweisen.
Das Exception
, nach dem Sie gefragt haben, tritt auf, wenn Sie eine Variable deklarieren, aber kein Objekt erstellt haben. Wenn Sie versuchen, num
zu dereferenzieren, BEVOR Sie das Objekt erstellen, erhalten Sie NullPointerException
. In den einfachsten Fällen wird der Compiler das Problem abfangen und Sie wissen lassen, dass "num möglicherweise nicht initialisiert wurde", aber manchmal schreiben Sie Code, der das Objekt nicht direkt erstellt.
Sie können zum Beispiel eine Methode wie folgt haben:
%Vor% In diesem Fall erstellen Sie nicht das Objekt obj
, sondern nehmen an, dass es erstellt wurde, bevor die Methode doSomething
aufgerufen wurde. Leider ist es möglich, die Methode wie folgt aufzurufen:
In diesem Fall ist obj
gleich Null. Wenn die Methode etwas mit dem übergebenen Objekt tun soll, ist es angebracht, NullPointerException
zu werfen, weil es sich um einen Programmierfehler handelt und der Programmierer diese Information zu Debugging-Zwecken benötigt.
Alternativ kann es Fälle geben, in denen der Zweck der Methode nicht nur darin besteht, mit dem übergebenen Objekt zu arbeiten, und daher ein Null-Parameter akzeptabel sein kann. In diesem Fall müssten Sie nach einem Null-Parameter suchen und sich anders verhalten. Sie sollten dies auch in der Dokumentation erläutern. Zum Beispiel könnte doSomething
wie folgt geschrieben werden:
Zum Schluss: Wie Sie den Ausnahmeort & amp; Ursache für die Verwendung von Stack Trace
NullPointerException
s sind Ausnahmen, die auftreten, wenn Sie versuchen, einen Verweis zu verwenden, der auf keinen Speicherort im Speicher verweist (null), als ob er auf ein Objekt verweist. Wenn Sie eine Methode für eine Nullreferenz aufrufen oder versuchen, auf ein Feld einer Nullreferenz zuzugreifen, wird NullPointerException
ausgelöst. Diese sind am häufigsten, aber andere Möglichkeiten sind auf der NullPointerException
Javadoc-Seite.
Der wahrscheinlich schnellste Beispielcode, den ich zur Veranschaulichung eines NullPointerException
erstellen könnte, wäre:
In der ersten Zeile in main
setze ich explizit Object
reference obj
auf null
. Das bedeutet, ich habe eine Referenz, aber sie zeigt nicht auf ein Objekt. Danach versuche ich, die Referenz so zu behandeln, als ob sie auf ein Objekt zeigt, indem ich eine Methode darauf anrufe. Dies führt zu NullPointerException
, da an der Stelle, auf die die Referenz verweist, kein Code ausgeführt werden muss.
(Dies ist ein technischer Aspekt, aber ich denke, es erwähnt: Ein Verweis, der auf Null zeigt, ist nicht dasselbe wie ein C-Zeiger, der auf einen ungültigen Speicherort zeigt. Ein Nullzeiger zeigt nirgends , was subtil anders ist, als auf einen Ort zu zeigen, der zufällig ungültig ist.)
Ein guter Ausgangspunkt sind die JavaDocs . Sie haben dies abgedeckt:
Wird ausgelöst, wenn eine Anwendung versucht, in einem Fall null zu verwenden Objekt ist erforderlich. Dazu gehören:
- Aufruf der Instanzmethode eines Null-Objekts.
- Auf das Feld eines Nullobjekts zugreifen oder dieses ändern.
- Die Länge von null als wäre es ein Array.
- Auf die Slots von null zugreifen oder sie ändern, als wäre es ein Array.
- Nullen wird geworfen, als wäre es ein Throwable-Wert.
Anwendungen sollten Instanzen dieser Klasse abwerfen, um andere anzugeben Illegale Verwendung des Null-Objekts.
Wenn Sie versuchen, einen NULL-Verweis mit synchronized
zu verwenden, wird auch diese Ausnahme ausgelöst. nach der JLS :
%Vor%
- Andernfalls, wenn der Wert des Ausdrucks null ist, wird ein
NullPointerException
geworfen.
Sie haben also ein NullPointerException
. Wie reparierst du es? Nehmen wir ein einfaches Beispiel, das ein NullPointerException
:
Identifizieren Sie die Nullwerte
Der erste Schritt besteht darin, genau zu identifizieren, welche Werte die Ausnahme verursachen . Dafür müssen wir etwas debuggen. Es ist wichtig zu lernen, einen Stacktrace zu lesen. Dies zeigt Ihnen, wo die Ausnahme ausgelöst wurde:
%Vor% Hier sehen wir, dass die Ausnahme in Zeile 13 (in der Methode printString
) ausgelöst wird. Sehen Sie sich die Zeile an und prüfen Sie, um welche Werte es sich bei null handelt
Hinzufügen von Protokollierungsanweisungen oder Verwenden eines Debuggers . Wir finden heraus, dass s
gleich null ist und der Aufruf der Methode length
die Ausnahme auslöst. Wir können sehen, dass das Programm aufhört, die Ausnahme auszulösen, wenn s.length()
aus der Methode entfernt wird.
Verfolgen Sie, woher diese Werte stammen
Als nächstes überprüfen Sie, woher dieser Wert kommt. Indem wir den Aufrufern der Methode folgen, sehen wir, dass s
mit printString(name)
in der Methode print()
übergeben wird und this.name
null ist.
Verfolgen Sie, wo diese Werte festgelegt werden sollen
Wo ist this.name
gesetzt? In der setName(String)
-Methode. Mit etwas mehr Debuggen können wir sehen, dass diese Methode überhaupt nicht aufgerufen wird. Wenn die Methode aufgerufen wurde, überprüfen Sie die Reihenfolge , ob diese Methoden aufgerufen werden, und die Methode set wird nicht nach der Druckmethode aufgerufen.
Das ist genug, um uns eine Lösung zu geben: Fügen Sie einen Aufruf von printer.setName()
hinzu, bevor Sie printer.print()
aufrufen.
Die Variable kann einen Standardwert haben (und setName
kann verhindern, dass sie auf null gesetzt wird):
Entweder die Methode print
oder printString
kann auf null prüfen, zum Beispiel:
Oder Sie können die Klasse so entwerfen, dass name
immer einen Wert ungleich Null hat :
Siehe auch:
Wenn Sie versucht haben, das Problem zu beheben und immer noch keine Lösung haben, können Sie eine Frage für weitere Hilfe stellen, aber stellen Sie sicher, dass Sie das, was Sie bisher versucht haben, einbeziehen. Mindestens enthält das Stacktrace in der Frage und markiert die wichtigen Zeilennummern im Code. Versuchen Sie auch, den Code zuerst zu vereinfachen (siehe SSCCE ).
NullPointerException
(NPE)? Wie Sie wissen sollten, sind Java-Typen in primitive Typen ( boolean
, int
usw.) und Referenztypen unterteilt. Referenztypen in Java erlauben Ihnen, den speziellen Wert null
zu verwenden, was die Java-Art ist, "kein Objekt" zu sagen.
Ein NullPointerException
wird zur Laufzeit ausgelöst, wenn Ihr Programm versucht, ein null
zu verwenden, als wäre es eine echte Referenz. Zum Beispiel, wenn Sie dies schreiben:
Die Anweisung "HIER" wird versuchen, die length()
-Methode für einen null
-Referenz auszuführen, und dies wird ein NullPointerException
werfen.
Es gibt viele Möglichkeiten, einen null
-Wert zu verwenden, der zu einem NullPointerException
führt. Die einzigen Dinge, die Sie mit einem null
ausführen können, ohne eine NPE zu verursachen, sind:
==
oder !=
oder instanceof
. Angenommen, ich kompiliere und führe das obige Programm aus:
%Vor% Erste Beobachtung: Die Kompilation ist erfolgreich! Das Problem im Programm ist KEIN Kompilierungsfehler. Es ist ein Fehler Laufzeit . (Einige IDEs warnen möglicherweise, dass Ihr Programm immer eine Ausnahme auslöst ... aber der standardmäßige javac
Compiler tut dies nicht.)
Zweite Beobachtung: Wenn ich das Programm laufe, gibt es zwei Zeilen "gobleddy-gook" aus. FALSCH !! Das ist kein Kauderwelsch. Es ist ein StackTrace ... und liefert wichtige Informationen , die Ihnen helfen, den Fehler in Ihrem Code aufzuspüren, wenn Sie sich die Zeit nehmen, ihn sorgfältig zu lesen.
Sehen wir uns also an, was es sagt:
%Vor%Die erste Zeile des Stack-Trace zeigt Ihnen eine Reihe von Dingen:
java.lang.NullPointerException
. NullPointerException
ist in dieser Hinsicht ungewöhnlich, da es selten eine Fehlermeldung gibt. Die zweite Zeile ist die wichtigste für die Diagnose einer NPE.
%Vor%Dies sagt uns eine Reihe von Dingen:
main
-Methode der Test
-Klasse befanden. Wenn Sie die Zeilen in der Datei oben zählen, ist Zeile 4 diejenige, die ich mit dem "HIER" -Kommentar beschriftet habe.
Beachten Sie, dass in einem komplizierteren Beispiel viele Zeilen in der NPE-Stack-Ablaufverfolgung vorhanden sind. Aber Sie können sicher sein, dass die zweite Zeile (die erste "at" -Zeile) Ihnen sagen wird, wo die NPE geworfen wurde 1 .
Kurz gesagt, der Stack-Trace wird uns eindeutig sagen, welche Anweisung des Programms die NPE geworfen hat.
1 - Nicht ganz richtig. Es gibt Dinge, die verschachtelte Ausnahmen genannt werden ...
Das ist der schwierige Teil. Die kurze Antwort besteht darin, logische Folgerungen auf die vom Stack-Trace bereitgestellten Informationen, den Quellcode und die relevante API-Dokumentation anzuwenden.
Lassen Sie uns zuerst das einfache Beispiel (oben) erläutern. Wir beginnen damit, die Zeile zu betrachten, die der Stack-Trace uns mitgeteilt hat, wo die NPE passiert ist:
%Vor%Wie kann das eine NPE werfen?
Tatsächlich gibt es nur einen Weg: Es kann nur passieren, wenn foo
den Wert null
hat. Wir versuchen dann, die Methode length()
für null
und .... BANG!
Aber (ich höre Sie sagen) was ist, wenn die NPE in den length()
Methodenaufruf geworfen wurde?
Nun, wenn das passierte, würde der Stack-Trace anders aussehen. Die erste "at" -Zeile würde sagen, dass die Ausnahme in einer Zeile in der java.lang.String
-Klasse geworfen wurde, und die Zeile 4 von Test.java
wäre die zweite "at" -Zeile.
Woher kommt also null
? In diesem Fall ist es offensichtlich, und es ist offensichtlich, was wir tun müssen, um es zu beheben. (Weisen Sie foo
einen Wert ungleich null zu.)
OK, also versuchen wir ein etwas komplizierteres Beispiel. Dies erfordert einige logische Schlussfolgerungen .
%Vor%So, jetzt haben wir zwei "at" -Linien. Der erste ist für diese Zeile:
%Vor%und der zweite ist für diese Zeile:
%Vor%Betrachtet man die erste Zeile, wie könnte das eine NPE werfen? Es gibt zwei Möglichkeiten:
bar
null
ist, dann wird bar[pos]
eine NPE werfen. bar[pos]
null
ist, dann ruft das Aufrufen von length()
eine NPE auf.Als nächstes müssen wir herausfinden, welches dieser Szenarien erklärt, was tatsächlich passiert. Wir beginnen mit der Erkundung des ersten:
Woher kommt bar
? Es ist ein Parameter für den Methodenaufruf test
, und wenn wir uns ansehen, wie test
aufgerufen wurde, können wir sehen, dass es von der statischen Variable foo
kommt. Außerdem können wir klar sehen, dass foo
auf einen Nicht-Null-Wert initialisiert wurde. Das reicht aus, um diese Erklärung vorläufig zu verwerfen. (Theoretisch könnte etwas anderes ändern foo
zu null
... aber das passiert hier nicht.)
Was ist mit unserem zweiten Szenario? Nun, wir können sehen, dass pos
ist 1
, so dass foo[1]
muss null
sein. Ist das möglich?
Tatsächlich ist es! Und das ist das Problem. Wenn wir so initialisieren:
%Vor% Wir weisen String[]
mit zwei Elementen zu, die auf null
initialisiert werden. Danach haben wir den Inhalt von foo
... nicht geändert, so dass foo[1]
immer noch null
ist.
Es ist, als ob Sie versuchen, auf ein Objekt zuzugreifen, das null
ist.
Beachten Sie das folgende Beispiel.
Zu diesem Zeitpunkt haben Sie nur dieses Objekt deklariert, aber nicht initialisiert oder instanziiert . Und wann immer Sie versuchen, auf eine Eigenschaft oder Methode zuzugreifen, wird NullPointerException
ausgegeben, was Sinn macht.
Siehe auch das folgende Beispiel.
%Vor%Eine Nullzeiger-Ausnahme wird ausgelöst, wenn eine Anwendung in einem Fall, in dem ein Objekt benötigt wird, versucht, null zu verwenden. Dazu gehören:
null
-Objekts. null
-Objekts. null
so, als wäre es ein Array. null
zugreifen oder sie ändern, als wäre es ein Array. null
wird geworfen, als wäre es ein Throwable-Wert. Anwendungen sollten Instanzen dieser Klasse auslösen, um auf andere illegale Verwendungen des null
-Objekts hinzuweisen.
Referenz: Ссылка
Ein NULL
-Zeiger ist einer, der nach nirgendwo zeigt. Wenn Sie einen Zeiger p
dereferenzieren, sagen Sie "geben Sie mir die Daten an dem Speicherort in" p ". Wenn p
ein Null-Zeiger ist, ist die in p
gespeicherte Position nowhere
, sagen Sie "Gib mir die Daten an der Stelle 'Nirgendwo'". Offensichtlich kann es das nicht, also wirft es ein NULL pointer exception
.
Im Allgemeinen liegt das daran, dass etwas nicht richtig initialisiert wurde.
Es gibt bereits viele Erklärungen, die erklären, wie es passiert und wie Sie es beheben können. Sie sollten jedoch Best Practices befolgen, um NullPointerException
überhaupt zu vermeiden.
Siehe auch: Eine gute Liste der Best Practices
Ich würde hinzufügen, sehr wichtig, nutze den final
Modifikator gut.
Verwenden des Modifizierers "final", wenn zutreffend in Java
Zusammenfassung:
final
, um eine gute Initialisierung zu erzwingen. @NotNull
und @Nullable
if("knownObject".equals(unknownObject)
valueOf()
über toString (). StringUtils
methods StringUtils.isEmpty(null)
. Eine Nullzeigerausnahme ist ein Indikator, dass Sie ein Objekt verwenden, ohne es zu initialisieren.
Zum Beispiel ist unten eine Schülerklasse, die sie in unserem Code verwenden wird.
%Vor%Der folgende Code gibt Ihnen eine Nullzeigerausnahme.
%Vor% Weil du Obj_Student
benutzt hast, aber du hast vergessen es zu initialisieren wie in der
korrekter Code unten gezeigt:
In Java ist alles in der Form einer Klasse.
Wenn Sie ein Objekt verwenden möchten, haben Sie zwei Phasen:
Beispiel:
int a;
a=0;
Gleiches gilt für das Array-Konzept
Item i[]=new Item[5];
i[0]=new Item();
Wenn Sie den Initialisierungsabschnitt nicht angeben, entsteht die NullpointerException
.
In Java sind alle von Ihnen deklarierten Variablen tatsächlich "Verweise" auf die Objekte (oder Primitive) und nicht die Objekte selbst.
Wenn Sie versuchen, eine Objektmethode auszuführen, fordert die Referenz das Objekt living auf, diese Methode auszuführen. Aber wenn die Referenz auf NULL verweist (nichts, null, void, nada), gibt es keine Möglichkeit, die Methode auszuführen. Dann lässt Sie die Laufzeit wissen, indem Sie eine NullPointerException werfen.
Ihre Referenz verweist auf null, also "Null - Zeiger".
Das Objekt befindet sich im VM-Speicherbereich und die einzige Möglichkeit, darauf zuzugreifen, ist die Verwendung von this
references. Nimm dieses Beispiel:
Dies ist wichtig zu wissen - wenn es keine Referenzen mehr auf ein Objekt gibt (im Beispiel oben, wenn reference
und otherReference
auf null zeigen), dann ist das Objekt "nicht erreichbar". Es gibt keine Möglichkeit, damit zu arbeiten, daher wird dieses Objekt als "Garbage Collected" markiert, und irgendwann wird die VM den Speicher freigeben, der von diesem Objekt verwendet wird, und ein anderes zuweisen.
Ein weiteres Vorkommen von NullPointerException
tritt auf, wenn man ein Objekt-Array deklariert und dann sofort versucht, Elemente darin zu dereferenzieren.
Dieses spezielle NPE kann vermieden werden, wenn die Vergleichsreihenfolge umgekehrt wird; Verwenden Sie nämlich .equals
auf einem garantierten Nicht-Null-Objekt.
Alle Elemente innerhalb eines Arrays werden initialisiert ihr gemeinsamer Anfangswert ; Für alle Arten von Objekt-Arrays bedeutet dies, dass alle Elemente null
sind.
Sie müssen die Elemente im Array initialisieren, bevor auf sie zugreift oder die Dereferenzierung erfolgt.
%Vor%Tags und Links java nullpointerexception