未初始化的String相 "+" 為什麼會打印出“nullnull"
阿新 • • 發佈:2018-12-23
今天在我的一個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的相加實際在變異後被處理成了StringBuilder的append.(注:我的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“,自然也就明白了。
這裡我想說的是,很多問題,可能表面上很簡單,或者我們可能會有很多想當然的想法,不過還是眼見為實,而且所有程式碼都放在那裡,我們為什麼不勤快的多翻開看看其中的實現,道理自然就在眼前。多動手,豐衣足食:)