Nessuna eccezione durante il cast del tipo con un null in Java


227
String x = (String) null;

Perché non ci sono eccezioni in questa affermazione?

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

Esso stampa null. Ma il .toString()metodo dovrebbe generare un'eccezione puntatore null.


di quale eccezione stai parlando, compilatore?
Sajan Chandran,

Risposte:


323

Puoi trasmettere nulla qualsiasi tipo di riferimento senza ottenere alcuna eccezione.

Il printlnmetodo non genera un puntatore nullo perché controlla innanzitutto se l'oggetto è nullo o meno. Se null, stampa semplicemente la stringa "null". Altrimenti chiamerà il toStringmetodo di quell'oggetto.

Aggiunta di ulteriori dettagli: i metodi di stampa interni chiamano il String.valueOf(object)metodo sull'oggetto di input. E nel valueOfmetodo, questo controllo aiuta a evitare l'eccezione del puntatore null:

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

Per il resto della tua confusione, chiamare qualsiasi metodo su un oggetto null dovrebbe generare un'eccezione puntatore null, se non un caso speciale.


1
@JunedAhsan quali casi speciali potrebbero causare il mancato lancio di un NPE?
Holloway,

@Trengot Controlla quello menzionato nella risposta di Peter di seguito.
Juned Ahsan,

144

Puoi trasmettere nulla qualsiasi tipo di riferimento. Puoi anche chiamare metodi che gestiscono a nullcome argomento, ad es. System.out.println(Object), Ma non puoi fare riferimento a un nullvalore e chiamare un metodo su di esso.

A proposito, c'è una situazione difficile in cui sembra che puoi chiamare metodi statici su nullvalori.

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

12
Wow. Se richiesto, sarei sicuro al 100% che genererebbe un'eccezione. Un caso davvero complicato.
Magnilex,

2
@Magnilex: Assolutamente! questa è una tipica domanda per l'esame OCPJP.
ccpizza,

3
Non è perché il compilatore in bytecode lo "ottimizza" t.yield() -> Thread.yeld() comunque? Simile a come final int i = 1; while (i == 1)è ottimizzato perwhile(true)
SGal

@SGal È ancora meglio perché la seconda ottimizzazione è AFAIK non obbligatoria mentre la prima è un po '.
Paul Stelian,

36

Questo è di progettazione. Puoi trasmettere nulla qualsiasi tipo di riferimento. Altrimenti non saresti in grado di assegnarlo a variabili di riferimento.


Grazie! questa nota relativa all'assegnazione di null alle variabili di riferimento è davvero utile!
Max

22

Il cast di valori null è necessario per il seguente costrutto in cui un metodo è sovraccarico e se null viene passato a questi metodi sovraccarichi, il compilatore non sa come chiarire l'ambiguità, quindi in questi casi è necessario digitare nullo in questi casi:

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);

Altrimenti non potresti chiamare il metodo che ti serve.


Nella maggior parte dei casi, il cast è implicito, ad esempio String bar = null;lancia il nullvalore su String. Finora ho dovuto solo lanciare null esplicitamente in un test in cui un metodo era sovraccarico e volevo testare il suo comportamento con input null. Comunque, buono a sapersi, stavo per scrivere una risposta simile prima di trovare la tua.
Vlasec,

Curiosità: l instanceof Longe s instanceof Stringtorneremo falsein questi casi.
Attila Tanyi,

7

Println(Object) usi String.valueOf()

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

Print(String) verifica null.

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


3

Come altri hanno scritto, puoi lanciare null su tutto. Normalmente, non ne avresti bisogno, puoi scrivere:

String nullString = null;

senza mettere lì il cast.

Ma ci sono occasioni in cui tali cast hanno senso:

a) se vuoi assicurarti che venga chiamato un metodo specifico, come:

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

allora farebbe la differenza se digiti

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

b) se si intende utilizzare il proprio IDE per generare codice; ad esempio, in genere scrivo unit test come:

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

Sto facendo TDD; ciò significa che probabilmente la classe "MyClassUnderTest" non esiste ancora. Scrivendo quel codice, posso quindi usare il mio IDE per generare prima la nuova classe; e quindi generare un costruttore che accetta un "qualunque" argomento "fuori dalla scatola" - l'IDE può capire dal mio test che il costruttore dovrebbe prendere esattamente un argomento di tipo qualunque.


2

Stampa :

Stampa un oggetto. La stringa prodotta dal metodo String.valueOf (Object) viene tradotta in byte

ValueOf :

se l'argomento è null, allora una stringa uguale a "null"; in caso contrario, viene restituito il valore di obj.toString ().

Restituirà semplicemente una stringa con valore "null" quando l'oggetto lo è null.


2

Questo è molto utile quando si utilizza un metodo che sarebbe altrimenti ambiguo. Ad esempio: JDialog ha costruttori con le seguenti firme:

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

Ho bisogno di usare questo costruttore, perché voglio impostare GraphicsConfiguration, ma non ho un genitore per questa finestra di dialogo, quindi il primo argomento dovrebbe essere nullo. utilizzando

JDialog(null, String, boolean, Graphicsconfiguration) 

è ambiguo, quindi in questo caso posso restringere la chiamata lanciando null su uno dei tipi supportati:

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

0

Questa funzionalità linguistica è utile in questa situazione.

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

Se memberHashMap.get ("Nome") restituisce null, si desidera comunque che il metodo sopra restituisca null senza generare un'eccezione. Qualunque sia la classe, null è null.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.