2011-09-10 183 views
11

在println中,這裏o.toString()拋出NPE但o1不。爲什麼?爲什麼null參考打印爲「null」

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

這是[全部在文檔中](http://download.oracle.com/javase/6/docs/api/java/io/PrintStream.html#print%28java.lang.Object%29)。 – 2011-09-10 20:28:52

回答

25

它可能有助於向您顯示字節碼。看看你的類的以下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 

} 

只看的主要方法,你可以看到感興趣的行是Code是8和33

代碼8顯示了字節碼爲你撥打o.toString()。這裏onull所以任何在null上調用方法的嘗試都會導致NullPointerException

代碼18顯示您的null對象作爲參數傳遞給PrintStream.print()方法。綜觀此方法的源代碼,會告訴你爲什麼這樣做結果在NPE:

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

String.valueOf()將做到這一點與null S:

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

所以,你可以看到有是一個測試那裏處理null,並防止NPE。

+0

很好的答案,謝謝。 – abc

+1

不客氣。我經常發現查看'javap'輸出可以非常有見地。特別是使用AspectJ和其他代碼編織技術時 - 只是爲了確切看到他們對我的代碼做了些什麼! –

+0

無需查看代碼。這些都在文檔中。 'PrintStream :: println'表示它調用'String.valueOf',它明確指出:「如果參數爲null,則返回一個等於」null「的字符串;否則返回obj.toString()的值。 – njzk2

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

o.toString()試圖取消引用空對象,將其轉換爲字符串,將它傳遞給println之前。

System.out.print(o1); 

的被稱爲printprint(Object)變種,它本身就是檢查的對象不是繼續之前空。