java中的 字符拼接与StringBuilder
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 //变量 + 字符 生成StringBuilder
public void test_literal(){
String lit1 = "hello" + "world" + "~" ; //不生成StringBuilder
String lit2 = "hello" + 1 ; //不生成StringBuilder,1是字面常量
String lit3 = "hello1" ; //不生成StringBuilder,并且重用前面的"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" + "~" ; //不生成StringBuilder
String var1 = "hello" + Integer.valueOf(1) ; //生成,这里有个Integer类型变量
String var2 = "hello" + num2 ; //生成,num2是变量
String var3 = "hello" + bo2 ; //生成
String var4 = "hello" + str2 ; //生成,str2是String类型变量
String var5 = "hello" + f1 ; //生成,f1是float类型变量
}
对应的字节码为:
// access flags 0x1
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" + "!!!!!!" ; //不生成StringBuilder
String final1 = "hello" + bo1 ; //不生成,bo1 final
String final2 = "hello" + num1 ; //不生成,num1 final
String final3 = "hello" + f1 ; //不生成,f1 final
String final4 = "hello" + str1 ; //不生成,str1 final
final1 += "java" ; //生成,这里是 += ,且final1是变量。
}
代码中前面几个都是final的,字节码为:
// access flags 0x1
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 = txt + "item" + i
所以 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