最近開始上班,路上時間變長爲1小時,目前還沒找到路上可以乾點啥。於是就刷刷公衆號文章,今天早上一不小心“偷看”了老王(公衆號:Java中文社區)的一篇關於String性能提升方法分析的文章。引發了一場底層代碼實現的探索。
老王的文章中關於字符串的處理和效率提升都沒錯,但在總結中提到“不要直接+=字符串”的建議卻引起我的懷疑。在路上就進行了評論:
“+=操作記得在最新版本是分場景的,比如正常來說沒有使用for循環這種情況,jdk默認會轉換StringBuilder來進行操作,而for循環內它會在for循環內不停的創建StringBuilder,所以才需要在外面聲明。”
老王的回覆是:我看很多資料也是這樣說,但jdk8和jdk11我反編譯都沒發現這種情況。
原本結論和建議是沒錯的,但技術人有時候就愛較個真。於是到公司的第一件事就是寫了兩個程序來驗證。
第一個程序:
public class TestString {
public static void main(String[] args) {
String a = "a";
String b = a + "b";
System.out.println(b);
}
}
先嚐試了反編譯,發現反編譯之後與源代碼一樣,也就是說通過反編譯看不出來差別。那就查看字節碼。
執行:
javap -c TestString.class
顯示結果:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2zAzdBbX-1588174039270)(http://www.choupangxia.com/wp-content/uploads/2020/04/string.jpg)]
通過字節碼看到,的確是被優化,創建了StringBuilder,然後再進行字符串拼接。隨後又驗證一下for循環的情況,是不是每次在for循環內部都會新創建一個StringBuilder。
public class TestString {
public static void main(String[] args) {
String a = "a";
for(int i=0; i< 3; i++){
a += ("a" + i);
}
System.out.println(a);
}
}
查看對應字節碼如下:
這裏在for循環中雖然沒有重複創建StringBuilder,但還是默認將String字符串轉換爲StringBuilder進行處理了。以上驗證採用的是Oracle官方jdk8進行測試的。
於是,開始給老王發信息,進行“挑戰”。不一會兒老王也發來回覆消息,說:爲什麼我都不是這樣呢?並附帶了截圖。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AXWATQz9-1588174039276)(http://www.choupangxia.com/wp-content/uploads/2020/04/string-2.jpg)]
一看他的截圖,還真是不一樣。於是開始一起比對環境,後來才發現他使用的是如下版本:
✗ java -version
'openjdk version "14" 2020-03-17
OpenJDK Runtime Environment (build 14+36-1461)
OpenJDK 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)
於是,一場爭辯結束,隨之大家共同發現一件事。網絡上流傳的JDK8默認幫忙優化String字符串拼接爲StringBuilder在openjdk的分支上並不成立,而在Oracle提供的JDK版本中才成立,而且要JDK8及以上版本。
其實經過幾輪的討論和各種嘗試,發現網絡上的一句話成立可能是有很多先決條件的,真是“理兒越變越明”。同時,技術也只有在這種碰撞中才能快速提升。
今天文章爲大家分享了一個技術點,學到了便是賺了。但如果你能通過整個事件的過程總結一套學習如何從分歧中獲得新知,如果從疑問中實踐出新知,那麼你真的是賺大發了。