1. 程式人生 > >未初始化的String相 "+" 為什麼會打印出“nullnull"

未初始化的String相 "+" 為什麼會打印出“nullnull"

今天在我的一個qq群裡有人問了這樣一個問題。

private static String a;

private static String b;

public static void main(String[] args) {

    String c = a+b;

    System.out.println(c);

}

輸出是nullnull。問為什麼是這樣。

其實問題並不複雜,很多同學也覺得自己知道原因,遂不予關注。但是我相信還是有初學Java的同學在這裡是存在誤會的。很典型的誤會就是如一個群裡的朋友說的String型別的變數如果沒有顯示初始化,預設的值就是”null”。支援的理由就是

private static String a;

public static void main(String[] args) {

System.out.println(a);

}

輸出是null

這個現象確實很容易迷惑一些初學的人,包括我也忽略了挺久。其實呢證明這種想法錯誤很簡單。如果預設值是null,那麼就意味著,該變數不是空(null)。而是字串的“null”

private static String a;

public static void main(String[] args) {

System.out.println(a==null);

System
.out.println("null".equals(a)); }

上述程式碼輸出分別是true,false。(呵呵,挺弱智的。)

說明String型別變數a,其實是空(null),而並沒有被賦值。那麼打印出null是為什麼呢?我們檢視PrintStream的原始碼就很清晰的明白了,其實是Java在println的時候進行了處理。

public void print(String s) {

if (s == null) {

s = "null";

}

write(s);

}

回到開頭的問題,既然沒有初始化賦值,那麼輸出為什麼是”nullnull“,兩個”null“連線的結果呢。這裡略微細說一下,檢視編譯過的class檔案,我們可以看到

public static void main(java.lang.String[] args);

0 new java.lang.StringBuilder [19]

3 dup

4 getstatic cn.home.pratice.jdk.string.StringMain.a : java.lang.String [21]

7 invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [23]

10 invokespecial java.lang.StringBuilder(java.lang.String) [29]

13 getstatic cn.home.pratice.jdk.string.StringMain.b : java.lang.String [32]

16 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [34]

19 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [38]

22 astore_1 [c][/c]

23 getstatic java.lang.System.out : java.io.PrintStream [42]

26 aload_1 [c][/c]

27 invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]

30 return System.out.println(c);

}

String的相加實際在變異後被處理成了StringBuilderappend.(注:我的JDK是1.6.0_u29)。那麼好,我們就應該檢視StringBuilder的原始碼,發現是呼叫的父類裡的方法,繼續檢視,道理就在這裡。

public StringBuilder append(String str) {

super.append(str);

return this;

}

public AbstractStringBuilder append(String str) {

if (str == null) str = "null";

int len = str.length();

if (len == 0) return this;

int newCount = count + len;

if (newCount > value.length)

expandCapacity(newCount);

str.getChars(0, len, value, count);

count = newCount;

return this;

}

原來也是對空null,進行了特殊的處理,那麼輸出是”nullnull“,自然也就明白了。

這裡我想說的是,很多問題,可能表面上很簡單,或者我們可能會有很多想當然的想法,不過還是眼見為實,而且所有程式碼都放在那裡,我們為什麼不勤快的多翻開看看其中的實現,道理自然就在眼前。多動手,豐衣足食:)