Perché il riferimento null viene stampato come “null”

In println, qui o.toString () lancia NPE ma o1, no. Perché?

public class RefTest { public static void main(String[] args) { Object o = null; Object o1 = null; System.out.println(o.toString()); //throws NPE System.out.print(o1); // does not throw NPE } } 

Potrebbe aiutarti a mostrarti il ​​bytecode. Dai un’occhiata al seguente output di javap della tua class:

 > javap -classpath target\test-classs -c RefTest Compiled from "RefTest.java" public class RefTest extends java.lang.Object{ public RefTest(); Code: 0: aload_0 1: invokespecial #8; //Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: aconst_null 1: astore_1 2: aconst_null 3: astore_2 4: getstatic #17; //Field java/lang/System.out:Ljava/io/PrintStream; 7: aload_1 8: invokevirtual #23; //Method java/lang/Object.toString:()Ljava/lang/String; 11: invokevirtual #27; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 14: getstatic #17; //Field java/lang/System.out:Ljava/io/PrintStream; 17: aload_2 18: invokevirtual #33; //Method java/io/PrintStream.print:(Ljava/lang/Object;)V 21: return } 

Solo guardando il metodo principale, puoi vedere le linee di interesse dove il Code è 8 e 33.

Il codice 8 mostra il bytecode per te che chiama o.toString() . Qui o è null e quindi qualsiasi tentativo di invocazione di un metodo su null risulta in una NullPointerException .

Il codice 18 mostra il tuo object null passato come parametro al metodo PrintStream.print() . Guardando il codice sorgente per questo metodo ti mostreremo il motivo per cui questo non risulta nell’NPE:

 public void print(Object obj) { write(String.valueOf(obj)); } 

e String.valueOf() farà questo con null s:

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

Quindi puoi vedere che c’è un test lì che si occupa di null e previene un NPE.

 System.out.println(o.toString()) 

o.toString() sta tentando di dereferenziare un object nullo per convertirlo in una stringa, prima di passarlo a println .

 System.out.print(o1); 

La print chiamata è la variante di print(Object) , che a sua volta controlla che l’object non sia null prima di procedere.

È perché print(Object) usa String.valueOf(Object) per la conversione (a parte: dopo la conversione println(Object) si comporterebbe come se fosse stata print(String) , print(Object) utilizza effettivamente write(int) ). String.valueOf(Object) non lancia l’NPE come o.toString() e viene invece definito per restituire "null" per un parametro null.