從java反編譯及字節(jié)碼角度探索分析String拼接字符串效率
前言
又刷到這篇文章
為什么idea建議去掉StringBuilder,使用“+”拼接字符串
網(wǎng)上有很多文章用 JUnit 進行測試驗證,可以網(wǎng)上搜一下,這里不做贅述。今天我們從反編譯和字節(jié)碼的角度分析字符串拼接的時候底層到底做了什么
拼接場景
示例 1:
public class Hello2 { public static void main(String[] args) { } public void add1() { String a = "aaa" + "bbb" + "ccc"; String b = new StringBuilder("aaa").append("bbb").append("ccc").toString(); } }
反編譯結(jié)果:
package com.noah.nowcoder; public class Hello2 { public static void main(String[] args) {} public void add1() { String a = "aaabbbccc"; String b = "aaa" + "bbb" + "ccc"; } }
Java 編譯器優(yōu)化(JDK 版本相關(guān)),編譯結(jié)果可以直接看出, String a = "aaa" + "bbb" + "ccc" 執(zhí)行效率更高;
示例 2:
public class Hello { public static void main(String[] args) { String str1 = ""; for (int i = 0; i < 100000; i++) { str1 += "-" + UUID.randomUUID().toString(); } System.out.println(str1); StringBuilder stringBuilder = new StringBuilder(); for(int i = 0; i < 100000; ++i) { stringBuilder.append("-").append(UUID.randomUUID().toString()); } System.out.println(stringBuilder.toString()); } }
反編譯結(jié)果:
package com.noah.nowcoder; import java.util.UUID; public class Hello { public static void main(String[] args) { String str1 = ""; for (int i = 0; i < 100000; i++) str1 = str1 + "-" + UUID.randomUUID().toString(); System.out.println(str1); StringBuilder stringBuilder = new StringBuilder(); for (int j = 0; j < 100000; j++) stringBuilder.append("-").append(UUID.randomUUID().toString()); System.out.println(stringBuilder.toString()); } }
這一步結(jié)果不明顯
字節(jié)碼信息
接下來,我們看一下字節(jié)碼信息
Compiled from "Hello.java" public class com.noah.nowcoder.Hello { public com.noah.nowcoder.Hello(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: ldc #3 // int 100000 8: if_icmpge 46 11: new #4 // class java/lang/StringBuilder 14: dup 15: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 18: aload_1 19: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 22: ldc #7 // String - 24: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 27: invokestatic #8 // Method java/util/UUID.randomUUID:()Ljava/util/UUID; 30: invokevirtual #9 // Method java/util/UUID.toString:()Ljava/lang/String; 33: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 36: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 39: astore_1 40: iinc 2, 1 43: goto 5 46: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream; 49: aload_1 50: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 53: new #4 // class java/lang/StringBuilder 56: dup 57: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 60: astore_2 61: iconst_0 62: istore_3 63: iload_3 64: ldc #3 // int 100000 66: if_icmpge 91 69: aload_2 70: ldc #7 // String - 72: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 75: invokestatic #8 // Method java/util/UUID.randomUUID:()Ljava/util/UUID; 78: invokevirtual #9 // Method java/util/UUID.toString:()Ljava/lang/String; 81: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 84: pop 85: iinc 3, 1 88: goto 63 91: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream; 94: aload_2 95: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 98: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 101: return }
注意:
15: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
調(diào)用了 StringBuilder 構(gòu)造函數(shù),初始化了一個 StringBuilder 對象(循環(huán)中初始化對象)
總結(jié)
根據(jù)字節(jié)碼改寫代碼
public void add2() { String str1 = ""; for (int i = 0; i < 100000; i++) { str1 += "-" + UUID.randomUUID().toString(); } System.out.println(str1); } public void add3() { String str1 = ""; for (int i = 0; i < 100000; i++) { StringBuilder stringBuilder = new StringBuilder(); str1 = stringBuilder.append(str1).append("-").append(UUID.randomUUID().toString()).toString(); } System.out.println(str1); }
字節(jié)碼文件:
public void add3(); Code: 0: ldc #10 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: ldc #11 // int 100000 8: if_icmpge 48 11: new #3 // class java/lang/StringBuilder 14: dup 15: invokespecial #12 // Method java/lang/StringBuilder."<init>":()V 18: astore_3 19: aload_3 20: aload_1 21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: ldc #13 // String - 26: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 29: invokestatic #14 // Method java/util/UUID.randomUUID:()Ljava/util/UUID; 32: invokevirtual #15 // Method java/util/UUID.toString:()Ljava/lang/String; 35: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 38: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 41: astore_1 42: iinc 2, 1 45: goto 5 48: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream; 51: aload_1 52: invokevirtual #17 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 55: return
從字節(jié)碼文件可以看出,add2() 和 add3() 基本上等價的。
所以循環(huán)中拼接字符串更高效的做法是將 StringBulider 放在循環(huán)外。
如下:
public static void main(String[] args) { StringBuilder stringBuilder = new StringBuilder(); for (int j = 0; j < 100000; j++) stringBuilder.append("-").append(UUID.randomUUID().toString()); System.out.println(stringBuilder.toString()); }
以上就是從java反編譯及字節(jié)碼角度探索分析String拼接字符串效率的詳細內(nèi)容,更多關(guān)于java String拼接字符串效率的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java Apache Shiro安全框架快速開發(fā)詳解流程
Apache Shiro是一個強大且易用的Java安全框架,執(zhí)行身份驗證、授權(quán)、密碼和會話管理。使用Shiro的易于理解的API,您可以快速、輕松地獲得任何應(yīng)用程序,從最小的移動應(yīng)用程序到最大的網(wǎng)絡(luò)和企業(yè)應(yīng)用程序2021-10-10Java編程實現(xiàn)對象克?。◤?fù)制)代碼詳解
這篇文章主要介紹了Java編程實現(xiàn)對象克隆(復(fù)制)代碼詳解,涉及了克隆的原因,如何實現(xiàn)克隆,克隆的一般步驟,深克隆與淺克隆的介紹等相關(guān)內(nèi)容,具有一定借鑒價值,需要的朋友可以參考下。2017-11-11SpringBoot2零基礎(chǔ)到精通之JUnit 5與指標監(jiān)控
SpringBoot是一種整合Spring技術(shù)棧的方式(或者說是框架),同時也是簡化Spring的一種快速開發(fā)的腳手架,本篇讓我們一起學習JUnit 5與指標監(jiān)控2022-03-03Java使用TCP實現(xiàn)數(shù)據(jù)傳輸實例詳解
這篇文章主要介紹了Java使用TCP實現(xiàn)數(shù)據(jù)傳輸實例詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06