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.

Vicky
quelle
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.

Juned Ahsan
quelle
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.
Peter Lawrey
quelle
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.

André Stannek
quelle
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.

Mewel
quelle
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);
}
Rocketboy
quelle
5

Viele Antworten hier erwähnen bereits

Sie können für jeden Referenztyp null umwandeln

und

Wenn das Argument null ist, ist eine Zeichenfolge gleich "null".

Ich habe mich gefragt, wo das angegeben ist, und in der Java-Spezifikation nachgeschlagen:

Die Nullreferenz kann jederzeit einem beliebigen Referenztyp zugewiesen oder umgewandelt werden (§5.2, §5.3, §5.5).

Wenn die Referenz null ist, wird sie in die Zeichenfolge "null" konvertiert (vier ASCII-Zeichen n, u, l, l).

Arigion
quelle
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.

GhostCat
quelle
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.

Jeroen Vannevel
quelle
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)
Marten Jacobs
quelle
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.

Changgull Song
quelle