一道有趣的 Java 基礎(chǔ)題
早期文章
問(wèn)題
在一個(gè) Java 群里有位群友分享了一道關(guān)于 Java 的題目,問(wèn)代碼是否拋異常。代碼如下:
public class Hello {static String a, b;public static void main(String[] argc) {a = a + b;System.out.println(a);}}
對(duì)于該問(wèn)題,我只知道是不會(huì)拋出異常的,但是對(duì)于輸出的結(jié)果我認(rèn)為是空字符串。不知道大家是怎么考慮的。后來(lái)這位群友,給出的答案是不會(huì)拋出異常,輸出的結(jié)果是 nullnull,且計(jì)算長(zhǎng)度是 8 。感覺(jué)比較有意思,就自己分析了一下。
測(cè)試
在對(duì)這個(gè)結(jié)果產(chǎn)生興趣時(shí),我先進(jìn)行了測(cè)試,將代碼進(jìn)行編譯并運(yùn)行,輸出情況如下:
:\Users\Administrator\Desktop> java Hellonullnull
肉眼直接觀察,輸出的結(jié)果的確是 nullnul,而長(zhǎng)度也肯定是 8。那么為什么呢?還是需要從 Java 的內(nèi)部去進(jìn)行了解。
分析
分析的最直接的方法應(yīng)該是看 JDK 的源碼,但是 JDK 的代碼浩如煙海,不知從何看起。那么就直接看其反匯編代碼。其反匯編代碼如下:
0: new #2 // class java/lang/StringBuilder3: dup4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V7: getstatic #4 // Field a:Ljava/lang/String;10: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;13: getstatic #6 // Field b:Ljava/lang/String;16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;22: putstatic #4 // Field a:Ljava/lang/String;25: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;28: getstatic #4 // Field a:Ljava/lang/String;31: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V34: return
我沒(méi)有了解過(guò) JVM 的指令,但是我了解過(guò)安卓 Dalvik 的 Smali 指令。兩者在設(shè)計(jì)上雖然有所區(qū)別,但是實(shí)際還是比較相似的。不過(guò)本身這種虛擬機(jī)的指令抽象程度較高,也算是比較好理解。那么,這里我們就來(lái)看 StringBuilder 的 append 方法的源碼(如果不看反匯編代碼,我根本想不到這里要看的是 StringBuilder 類的 append 方法)。雖然,StringBuilder 有多個(gè)重載的 append 方法,但是根據(jù)反匯編指令也能夠知道具體調(diào)用的是哪個(gè)方法。其源碼如下:
public StringBuilder append(String str) {super.append(str);return this;}
這里直接調(diào)用了其父類的方法,接著往上看它的代碼,代碼如下:
public AbstractStringBuilder append(String str) {if (str == null)return appendNull();int len = str.length();ensureCapacityInternal(count + len);str.getChars(0, len, value, count);count += len;return this;}
該代碼在 AbstractStringBuilder 類中,通過(guò)上面的代碼可以知道,當(dāng) str 為 null 時(shí),會(huì)調(diào)用 appendNull 方法,該方法的代碼如下:
private AbstractStringBuilder appendNull() {int c = count;ensureCapacityInternal(c + 4);final char[] value = this.value;value[c++] = 'n';value[c++] = 'u';value[c++] = 'l';value[c++] = 'l';count = c;return this;}
從以上代碼就不難看出,輸出結(jié)果為什么是 nullnull 的情況了。
小結(jié)
這樣的問(wèn)題意義何在呢?我個(gè)人覺(jué)得,在項(xiàng)目中總會(huì)出現(xiàn)各種奇奇怪怪的問(wèn)題,而一些奇奇怪怪的問(wèn)題卻是我們平時(shí)疏忽的基礎(chǔ)或細(xì)節(jié)造成的,因此也在空閑之余,多多關(guān)注基礎(chǔ)知識(shí)和技術(shù)細(xì)節(jié),會(huì)有助于自己解決很多奇奇怪怪的問(wèn)題。
更多文章
