Keine Ausnahme beim Typ-Casting mit einer Null in Java


227
String x = (String) null;

Warum gibt es in dieser Aussage keine Ausnahme?

String x = null;
System.out.println(x);

Es wird gedruckt null. Die .toString()Methode sollte jedoch eine Nullzeigerausnahme auslösen.


Von welcher Ausnahme sprichst du, Compiler?
Sajan Chandran

Antworten:


323

Sie können nullohne Ausnahme in einen beliebigen Referenztyp umwandeln.

Die printlnMethode löst keinen Nullzeiger aus, da zunächst geprüft wird, ob das Objekt null ist oder nicht. Wenn null, wird einfach die Zeichenfolge gedruckt "null". Andernfalls wird die toStringMethode dieses Objekts aufgerufen .

Hinzufügen weiterer Details: Interne Druckmethoden rufen die String.valueOf(object)Methode für das Eingabeobjekt auf. In der valueOfMethode hilft diese Prüfung, eine Nullzeigerausnahme zu vermeiden:

return (obj == null) ? "null" : obj.toString();

Für den Rest Ihrer Verwirrung sollte das Aufrufen einer Methode für ein Nullobjekt eine Nullzeigerausnahme auslösen, wenn nicht sogar einen Sonderfall.


1
@JunedAhsan Welche besonderen Fälle würden dazu führen, dass keine NPE geworfen wird?
Holloway

@Trengot Überprüfen Sie eine in Peter Antwort unten erwähnt.
Juned Ahsan

144

Sie können nullin einen beliebigen Referenztyp umwandeln. Sie können auch Methoden aufrufen, die a nullals Argument behandeln, z. B. System.out.println(Object), aber Sie können nicht auf einen nullWert verweisen und eine Methode darauf aufrufen.

Übrigens Es gibt eine schwierige Situation, in der Sie statische Methoden für nullWerte aufrufen können.

Thread t = null;
t.yield(); // Calls static method Thread.yield() so this runs fine.

12
Beeindruckend. Wenn ich gefragt würde, wäre ich zu 100% sicher, dass es eine Ausnahme auslösen würde. Ein schwieriger Fall.
Magnilex

2
@ Magnilex: Auf jeden Fall! Dies ist eine typische Trickfrage für OCPJP-Prüfungen.
ccpizza

3
Liegt das nicht daran, dass der Compiler im Bytecode ihn t.yield() -> Thread.yeld() trotzdem "optimiert" ? Ähnlich wie final int i = 1; while (i == 1)optimiert aufwhile(true)
SGal

@SGal Es ist sogar noch besser, weil die zweite Optimierung AFAIK nicht obligatorisch ist, während die erste irgendwie ist.
Paul Stelian

36

Dies ist beabsichtigt. Sie können nullin einen beliebigen Referenztyp umwandeln. Andernfalls könnten Sie es nicht Referenzvariablen zuweisen.


Vielen Dank! Dieser Hinweis zur Zuweisung von Null zu Referenzvariablen ist sehr hilfreich!
Max

22

Das Umwandeln von Nullwerten ist erforderlich für das folgende Konstrukt, bei dem eine Methode überladen ist. Wenn Null an diese überladenen Methoden übergeben wird, weiß der Compiler nicht, wie die Mehrdeutigkeit behoben werden kann. Daher müssen wir in diesen Fällen Null typisieren:

class A {
  public void foo(Long l) {
    // do something with l
  }
  public void foo(String s) {
    // do something with s      
  }
}
new A().foo((String)null);
new A().foo((Long)null);

Andernfalls könnten Sie die benötigte Methode nicht aufrufen.


In den meisten Fällen ist das Casting implizit, z. B. String bar = null;wirft den nullWert auf String. Bisher musste ich in einem Test, in dem eine Methode überladen war, nur explizit null umsetzen, und ich wollte ihr Verhalten mit null Eingaben testen. Gut zu wissen, dass ich gerade eine ähnliche Antwort schreiben wollte, bevor ich Ihre fand.
Vlasec

Lustige Tatsache: l instanceof Longund s instanceof Stringwird falsein diesen Fällen zurückkehren.
Attila Tanyi

7

Println(Object) Verwendet String.valueOf()

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Print(String) führt eine Nullprüfung durch.

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}


3

Wie andere geschrieben haben, können Sie für alles null setzen. Normalerweise würden Sie das nicht brauchen, Sie können schreiben:

String nullString = null;

ohne die Besetzung dort zu setzen.

Aber es gibt Fälle, in denen solche Darsteller Sinn machen:

a) Wenn Sie sicherstellen möchten, dass eine bestimmte Methode aufgerufen wird, wie z.

void foo(String bar) {  ... }
void foo(Object bar) {  ... }

dann würde es einen Unterschied machen, wenn Sie tippen

foo((String) null) vs. foo(null)

b) wenn Sie beabsichtigen, Ihre IDE zum Generieren von Code zu verwenden; Zum Beispiel schreibe ich normalerweise Unit-Tests wie:

@Test(expected=NullPointerException.class)
public testCtorWithNullWhatever() {
    new MyClassUnderTest((Whatever) null);
}

Ich mache TDD; Dies bedeutet, dass die Klasse "MyClassUnderTest" wahrscheinlich noch nicht existiert. Durch Aufschreiben dieses Codes kann ich dann mit meiner IDE zuerst die neue Klasse generieren. und um dann einen Konstruktor zu generieren, der ein "Whatever" -Argument "out of the box" akzeptiert - die IDE kann aus meinem Test herausfinden, dass der Konstruktor genau ein Argument vom Typ Whatever verwenden sollte.


2

Drucken :

Drucken Sie ein Objekt. Die von der String.valueOf (Object) -Methode erzeugte Zeichenfolge wird in Bytes übersetzt

ValueOf :

Wenn das Argument null ist, ist eine Zeichenfolge gleich "null". Andernfalls wird der Wert von obj.toString () zurückgegeben.

Es wird einfach eine Zeichenfolge mit dem Wert "null" zurückgegeben, wenn sich das Objekt befindet null.


2

Dies ist sehr praktisch, wenn Sie eine Methode verwenden, die ansonsten nicht eindeutig wäre. Beispiel: JDialog verfügt über Konstruktoren mit den folgenden Signaturen:

JDialog(Frame, String, boolean, GraphicsConfiguration)
JDialog(Dialog, String, boolean, GraphicsConfiguration)

Ich muss diesen Konstruktor verwenden, da ich die GraphicsConfiguration festlegen möchte, aber kein übergeordnetes Element für diesen Dialog habe. Daher sollte das erste Argument null sein. Verwenden von

JDialog(null, String, boolean, Graphicsconfiguration) 

ist mehrdeutig, daher kann ich in diesem Fall den Aufruf eingrenzen, indem ich null auf einen der unterstützten Typen umwandle:

JDialog((Frame) null, String, boolean, GraphicsConfiguration)

0

Diese Sprachfunktion ist in dieser Situation praktisch.

public String getName() {
  return (String) memberHashMap.get("Name");
}

Wenn memberHashMap.get ("Name") null zurückgibt, soll die obige Methode dennoch null zurückgeben, ohne eine Ausnahme auszulösen. Egal was die Klasse ist, null ist null.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.