1.要点
编译器会把 [ 变量 + "字符" ] 语句翻译成new 一个 StringBuilder对象并用它的append方法实现字符拼接。如果在循环语句中会频繁new StringBuilder对象,浪费时间。如:下面代码每次循环都生成两个StringBuilder对象。
| String txt = ""; |
| for (int i = 0 ; i < 4;++i){ |
| txt += "item" + i; |
| txt += "gggg" + i; |
| } |
字符串与变量相加生成StringBuilder,与常量、字面量相加不生成。
2.字符串与字面量相加
字符串与字面量相加,不生成StringBulder
| @Test |
| public void test_literal(){ |
| |
| String lit1 = "hello" + "world" + "~" ; |
| String lit2 = "hello" + 1 ; |
| String lit3 = "hello1" ; |
| String lit4 = "hello" + true ; |
| String lit5 = "hello" + 0.2f ; |
| |
| } |
对应的字节码为:并没有生成StringBuilder对象
| public test_literal()V |
| @Lorg/junit/Test;() |
| L0 |
| LINENUMBER 10 L0 |
| LDC "helloworld~" |
| ASTORE 1 |
| L1 |
| LINENUMBER 11 L1 |
| LDC "hello1" |
| ASTORE 2 |
| L2 |
| LINENUMBER 12 L2 |
| LDC "hello1" |
| ASTORE 3 |
| L3 |
| LINENUMBER 13 L3 |
| LDC "hellotrue" |
| ASTORE 4 |
| L4 |
| LINENUMBER 14 L4 |
| LDC "hello0.2" |
| ASTORE 5 |
| L5 |
| LINENUMBER 17 L5 |
| RETURN |
| L6 |
| LOCALVARIABLE this Lcom/example/sjjg/java/StringPlus; L0 L6 0 |
| LOCALVARIABLE lit1 Ljava/lang/String; L1 L6 1 |
| LOCALVARIABLE lit2 Ljava/lang/String; L2 L6 2 |
| LOCALVARIABLE lit3 Ljava/lang/String; L3 L6 3 |
| LOCALVARIABLE lit4 Ljava/lang/String; L4 L6 4 |
| LOCALVARIABLE lit5 Ljava/lang/String; L5 L6 5 |
| MAXSTACK = 1 |
| MAXLOCALS = 6 |
3.字符串与变量相加
字符串与变量相加,生成StringBuilder
| @Test |
| public void test2_variable(){ |
| float f1 = 1.0f; |
| boolean bo2 = true; |
| int num2 = 1; |
| String str2 = "hello" + "world" + "~" ; |
| |
| String var1 = "hello" + Integer.valueOf(1) ; |
| String var2 = "hello" + num2 ; |
| String var3 = "hello" + bo2 ; |
| String var4 = "hello" + str2 ; |
| String var5 = "hello" + f1 ; |
| } |
对应的字节码为:
| |
| public test2_variable()V |
| @Lorg/junit/Test;() |
| L0 |
| LINENUMBER 20 L0 |
| FCONST_1 |
| FSTORE 1 |
| L1 |
| LINENUMBER 21 L1 |
| ICONST_1 |
| ISTORE 2 |
| L2 |
| LINENUMBER 22 L2 |
| ICONST_1 |
| ISTORE 3 |
| L3 |
| LINENUMBER 23 L3 |
| LDC "helloworld~" |
| ASTORE 4 |
| L4 |
| LINENUMBER 25 L4 |
| NEW java/lang/StringBuilder |
| DUP |
| INVOKESPECIAL java/lang/StringBuilder.<init> ()V |
| LDC "hello" |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| ICONST_1 |
| INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer; |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder; |
| INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; |
| ASTORE 5 |
| L5 |
| LINENUMBER 26 L5 |
| NEW java/lang/StringBuilder |
| DUP |
| INVOKESPECIAL java/lang/StringBuilder.<init> ()V |
| LDC "hello" |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| ILOAD 3 |
| INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder; |
| INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; |
| ASTORE 6 |
| L6 |
| LINENUMBER 27 L6 |
| NEW java/lang/StringBuilder |
| DUP |
| INVOKESPECIAL java/lang/StringBuilder.<init> ()V |
| LDC "hello" |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| ILOAD 2 |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Z)Ljava/lang/StringBuilder; |
| INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; |
| ASTORE 7 |
| L7 |
| LINENUMBER 28 L7 |
| NEW java/lang/StringBuilder |
| DUP |
| INVOKESPECIAL java/lang/StringBuilder.<init> ()V |
| LDC "hello" |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| ALOAD 4 |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; |
| ASTORE 8 |
| L8 |
| LINENUMBER 29 L8 |
| NEW java/lang/StringBuilder |
| DUP |
| INVOKESPECIAL java/lang/StringBuilder.<init> ()V |
| LDC "hello" |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| FLOAD 1 |
| INVOKEVIRTUAL java/lang/StringBuilder.append (F)Ljava/lang/StringBuilder; |
| INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; |
| ASTORE 9 |
| L9 |
| LINENUMBER 31 L9 |
| RETURN |
| L10 |
| LOCALVARIABLE this Lcom/example/sjjg/java/StringPlus; L0 L10 0 |
| LOCALVARIABLE f1 F L1 L10 1 |
| LOCALVARIABLE bo2 Z L2 L10 2 |
| LOCALVARIABLE num2 I L3 L10 3 |
| LOCALVARIABLE str2 Ljava/lang/String; L4 L10 4 |
| LOCALVARIABLE var1 Ljava/lang/String; L5 L10 5 |
| LOCALVARIABLE var2 Ljava/lang/String; L6 L10 6 |
| LOCALVARIABLE var3 Ljava/lang/String; L7 L10 7 |
| LOCALVARIABLE var4 Ljava/lang/String; L8 L10 8 |
| LOCALVARIABLE var5 Ljava/lang/String; L9 L10 9 |
| MAXSTACK = 2 |
| MAXLOCALS = 10 |
4.字符串与常量相加
字符串与常量相加,不生成StringBuilder
| @Test |
| public void test_final(){ |
| final float f1 = 1.0f; |
| final boolean bo1 = true; |
| final int num1 = 1; |
| final String str1 = "world" + "!!!!!!" ; |
| |
| String final1 = "hello" + bo1 ; |
| String final2 = "hello" + num1 ; |
| String final3 = "hello" + f1 ; |
| String final4 = "hello" + str1 ; |
| final1 += "java" ; |
| |
| } |
代码中前面几个都是final的,字节码为:
| |
| public test_final()V |
| @Lorg/junit/Test;() |
| L0 |
| LINENUMBER 34 L0 |
| FCONST_1 |
| FSTORE 1 |
| L1 |
| LINENUMBER 35 L1 |
| ICONST_1 |
| ISTORE 2 |
| L2 |
| LINENUMBER 36 L2 |
| ICONST_1 |
| ISTORE 3 |
| L3 |
| LINENUMBER 37 L3 |
| LDC "world!!!!!!" |
| ASTORE 4 |
| L4 |
| LINENUMBER 39 L4 |
| LDC "hellotrue" |
| ASTORE 5 |
| L5 |
| LINENUMBER 40 L5 |
| LDC "hello1" |
| ASTORE 6 |
| L6 |
| LINENUMBER 41 L6 |
| LDC "hello1.0" |
| ASTORE 7 |
| L7 |
| LINENUMBER 42 L7 |
| LDC "helloworld!!!!!!" |
| ASTORE 8 |
| L8 |
| LINENUMBER 43 L8 |
| NEW java/lang/StringBuilder |
| DUP |
| INVOKESPECIAL java/lang/StringBuilder.<init> ()V |
| ALOAD 5 |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| LDC "java" |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; |
| ASTORE 5 |
| L9 |
| LINENUMBER 45 L9 |
| RETURN |
| L10 |
| LOCALVARIABLE this Lcom/example/sjjg/java/StringPlus; L0 L10 0 |
| LOCALVARIABLE f1 F L1 L10 1 |
| LOCALVARIABLE bo1 Z L2 L10 2 |
| LOCALVARIABLE num1 I L3 L10 3 |
| LOCALVARIABLE str1 Ljava/lang/String; L4 L10 4 |
| LOCALVARIABLE final1 Ljava/lang/String; L5 L10 5 |
| LOCALVARIABLE final2 Ljava/lang/String; L6 L10 6 |
| LOCALVARIABLE final3 Ljava/lang/String; L7 L10 7 |
| LOCALVARIABLE final4 Ljava/lang/String; L8 L10 8 |
| MAXSTACK = 2 |
| MAXLOCALS = 9 |
5.循环中的字符串相加
5.1 示例1
| String txt = ""; |
| for (int i = 0 ; i < 10;++i){ |
| txt += "item" + i; |
| } |
代码中txt += "item" + 1,的翻译过程是
所以 txt + "item" 会先生成一个StringBuilder对象,又与i相加,这片代码会产生警告 String concatenation '+=' in loop ,对应的字节码为:
| L2 |
| LINENUMBER 11 L2 |
| LDC "" |
| ASTORE 3 |
| L3 |
| LINENUMBER 12 L3 |
| ICONST_0 |
| ISTORE 4 |
| L4 |
| FRAME FULL [com/example/sjjg/java/StringPlus java/lang/String java/lang/String java/lang/String I] [] |
| ILOAD 4 |
| ICONST_4 |
| IF_ICMPGE L5 |
| L6 |
| LINENUMBER 13 L6 |
| NEW java/lang/StringBuilder |
| DUP |
| INVOKESPECIAL java/lang/StringBuilder.<init> ()V |
| ALOAD 3 |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| LDC "item" |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| ILOAD 4 |
| INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder; |
| INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; |
| ASTORE 3 |
| L7 |
| LINENUMBER 12 L7 |
| IINC 4 1 |
| GOTO L4 |
5.2 示例2
| StringBuilder buffer = new StringBuilder(); |
| for (int i = 0 ; i < 4;++i){ |
| buffer.append("buffer1" + i); |
| buffer.append("buffer2").append(i); |
| } |
- 上述代码中有两个StringBuilder,一个是buffer,一个是"buffer1" + i 生成 的,
- buffer.append("buffer1" + i);是错误写法,buffer.append("buffer2").append(i);的是正确写法。
- 字节码如下:
| L5 |
| LINENUMBER 15 L5 |
| FRAME CHOP 1 |
| NEW java/lang/StringBuilder |
| DUP |
| INVOKESPECIAL java/lang/StringBuilder.<init> ()V |
| ASTORE 4 |
| L8 |
| LINENUMBER 16 L8 |
| ICONST_0 |
| ISTORE 5 |
| L9 |
| FRAME APPEND [java/lang/StringBuilder I] |
| ILOAD 5 |
| ICONST_4 |
| IF_ICMPGE L10 |
| L11 |
| LINENUMBER 17 L11 |
| ALOAD 4 |
| NEW java/lang/StringBuilder |
| DUP |
| INVOKESPECIAL java/lang/StringBuilder.<init> ()V |
| LDC "buffer1" |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| ILOAD 5 |
| INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder; |
| INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| POP |
| L12 |
| LINENUMBER 18 L12 |
| ALOAD 4 |
| LDC "buffer2" |
| INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; |
| ILOAD 5 |
| INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder; |
| POP |
| L13 |
| LINENUMBER 16 L13 |
| IINC 5 1 |
| GOTO L9 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?