¿Por qué la referencia nula se imprime como “nula”?

En println, aquí o.toString () arroja NPE pero o1, no. ¿Por qué?

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 } } 

Podría ayudar a mostrarle el bytecode. Eche un vistazo a la siguiente salida de javap de su clase:

 > javap -classpath target\test-classes -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 mirando el método principal, puede ver las líneas de interés donde Code es 8 y 33.

El código 8 muestra el bytecode para usted que llama a o.toString() . Aquí o es null por lo que cualquier bash de invocación de un método en null da como resultado una NullPointerException .

El código 18 muestra que su objeto null se pasa como parámetro del método PrintStream.print() . Si mira el código fuente de este método, le mostrará por qué esto no da como resultado el NPE:

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

y String.valueOf() hará esto con null s:

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

Entonces puede ver que hay una prueba que trata con null , y previene un NPE.

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

o.toString() intenta desreferenciar un objeto nulo para convertirlo en una cadena, antes de pasarlo a println .

 System.out.print(o1); 

La print se llama es la variante de print(Object) , que a su vez verifica que el objeto no sea nulo antes de continuar.

Es porque print(Object) usa String.valueOf(Object) para la conversión (aparte: después de la conversión println(Object) se comportaría como si se llamara print(String) , print(Object) utiliza efectivamente write(int) ). String.valueOf(Object) no arroja el NPE como lo hace o.toString() y en su lugar se define para devolver "null" para un parámetro nulo.