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

 

posted @ 2015-05-03 15:26  f9q  阅读(310)  评论(0编辑  收藏  举报