为什么空引用打印为“空”

2022-09-05 00:31:54

在 println 中,这里 o.toString() 抛出 NPE,但 o1 不会。为什么?

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

答案 1

它可能有助于向您显示字节码。请看一下类的以下输出:javap

> 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."<init>":()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

}

只要看一下主方法,你可以看到感兴趣的线在哪里是8和33。Code

代码 8 显示调用 的字节码。这里是,因此,对方法调用的任何尝试都会导致 .o.toString()onullnullNullPointerException

代码 18 显示您的对象作为参数传递给方法。查看此方法的源代码将向您展示为什么这会导致 NPE:nullPrintStream.print()

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

并将使用 s 执行此操作:String.valueOf()null

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

所以你可以看到那里有一个测试来处理,并防止NPE。null


答案 2
System.out.println(o.toString())

o.toString()正在尝试取消引用空对象以将其转换为字符串,然后再将其传递给 。println

System.out.print(o1);

被调用的是变体,它本身是在继续之前检查对象是否不为空。printprint(Object)


推荐