java字符串连接StringBuilder,StringBuffer和+拼接区别是什么

java字符串连接StringBuilder,StringBuffer和+拼接区别是什么

经验文章nimo972025-04-26 18:48:032A+A-

环境

JDK17

StringBuffer和StringBuilder

StringBuffer和StringBuilder都继承了AbstractStringBuilder抽象类,底层都是可变的字符数组,所以在进行频繁的字符串操作时,建议使用StringBuffer和StringBuilder来进行操作。 StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。

代码

public class StringConcatenationInLoop {
    public static void main(String[] args) {
        String result = "";
        for (int i = 0; i < 10; i++) {
            result = new StringBuilder().append(result).append(i).toString();
        }
        System.out.println(result);
    }
}

编译后

// Source code is decompiled from a .class file using FernFlower decompiler.
package cn.goylsf.str;

class StringConcatenationInLoop {
   StringConcatenationInLoop() {
   }

   public static void main(String[] args) {
      String result = "";

      for(int i = 0; i < 10; ++i) {
         result = result + i;
      }

      System.out.println(result);
   }
}

javap -c -v .\StringConcatenationInLoop.class

 Classfile /C:/Java/workspace/myLabs/JavaBaseLab/target/classes/cn/goylsf/str/StringConcatenationInLoop.class
  Last modified 2025年4月5日; size 953 bytes
  SHA-256 checksum 2fd3c18a078351b593adc3f73d142ea4d2014046ce3733a939bfd10547b48250
  Compiled from "StringConcatenationInLoop.java"
class cn.goylsf.str.StringConcatenationInLoop
  minor version: 0
  major version: 52
  flags: (0x0020) ACC_SUPER
  this_class: #1                          // cn/goylsf/str/StringConcatenationInLoop
  super_class: #3                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Class              #2             // cn/goylsf/str/StringConcatenationInLoop
   #2 = Utf8               cn/goylsf/str/StringConcatenationInLoop
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcn/goylsf/str/StringConcatenationInLoop;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = String             #17            // 1
  #17 = Utf8               1
  #18 = Class              #19            // java/lang/StringBuilder
  #19 = Utf8               java/lang/StringBuilder
  #20 = Methodref          #21.#23        // java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
  #21 = Class              #22            // java/lang/String
  #22 = Utf8               java/lang/String
  #23 = NameAndType        #24:#25        // valueOf:(Ljava/lang/Object;)Ljava/lang/String;
  #24 = Utf8               valueOf
  #25 = Utf8               (Ljava/lang/Object;)Ljava/lang/String;
  #26 = Methodref          #18.#27        // java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
  #27 = NameAndType        #5:#28         // "<init>":(Ljava/lang/String;)V
  #28 = Utf8               (Ljava/lang/String;)V
  #29 = Methodref          #18.#30        // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  #30 = NameAndType        #31:#32        // append:(I)Ljava/lang/StringBuilder;
  #31 = Utf8               append
  #32 = Utf8               (I)Ljava/lang/StringBuilder;
  #33 = Methodref          #18.#34        // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #34 = NameAndType        #35:#36        // toString:()Ljava/lang/String;
  #35 = Utf8               toString
  #36 = Utf8               ()Ljava/lang/String;
  #37 = Fieldref           #38.#40        // java/lang/System.out:Ljava/io/PrintStream;
  #38 = Class              #39            // java/lang/System
  #39 = Utf8               java/lang/System
  #40 = NameAndType        #41:#42        // out:Ljava/io/PrintStream;
  #41 = Utf8               out
  #42 = Utf8               Ljava/io/PrintStream;
  #43 = Methodref          #44.#46        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #44 = Class              #45            // java/io/PrintStream
  #45 = Utf8               java/io/PrintStream
  #46 = NameAndType        #47:#28        // println:(Ljava/lang/String;)V
  #47 = Utf8               println
  #48 = Utf8               args
  #49 = Utf8               [Ljava/lang/String;
  #50 = Utf8               result
  #51 = Utf8               Ljava/lang/String;
  #52 = Utf8               i
  #53 = Utf8               I
  #54 = Utf8               StackMapTable
  #55 = Utf8               SourceFile
  #56 = Utf8               StringConcatenationInLoop.java
{
  cn.goylsf.str.StringConcatenationInLoop();
    descriptor: ()V
    flags: (0x0000)
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcn/goylsf/str/StringConcatenationInLoop;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=3, args_size=1
         0: ldc           #16                 // String 1
         2: astore_1
         3: iconst_0
         4: istore_2
         5: goto          30
         8: new           #18                 // class java/lang/StringBuilder
        11: dup
        12: aload_1
        13: invokestatic  #20                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
        16: invokespecial #26                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
        19: iload_2
        20: invokevirtual #29                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        23: invokevirtual #33                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        26: astore_1
        27: iinc          2, 1
        30: iload_2
        31: bipush        10
        33: if_icmplt     8
        36: getstatic     #37                 // Field java/lang/System.out:Ljava/io/PrintStream;
        39: aload_1
        40: invokevirtual #43                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        43: return
      LineNumberTable:
        line 5: 0
        line 6: 3
        line 7: 8
        line 6: 27
        line 9: 36
        line 10: 43
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      44     0  args   [Ljava/lang/String;
            3      41     1 result   Ljava/lang/String;
            5      31     2     i   I
      StackMapTable: number_of_entries = 2
        frame_type = 253 /* append */
          offset_delta = 8
          locals = [ class java/lang/String, int ]
        frame_type = 21 /* same */
}
SourceFile: "StringConcatenationInLoop.java"

字符串拼接的优化机制变化底层实现原理的演进

  1. JDK 8 及之前的策略
  • 编译器静态优化:将字符串的 + 操作直接转换为显式的 StringBuilder.append() 调用
  • 生成固定模式的字节码:通过查看反编译代码可见连续的 append() 和 toString() 调用。
  1. JDK 9+ 的 StringConcatFactory 机制
  • 动态调用站点绑定:通过 invokedynamic 指令在首次调用时绑定最优策略
  • 六种优化策略可选: o BC_SB(等价于旧版 StringBuilder) o BC_SB_SIZED(预计算长度的 StringBuilder) o BC_SB_SIZED_EXACT(精确长度预计算) o MH_SB(方法句柄组合) o MH_INLINE_SIZED_EXACT(内联复制) o 默认策略(自动选择最合适方案)。
点击这里复制本文地址 以上内容由nimo97整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

尼墨宝库 © All Rights Reserved.  蜀ICP备2024111239号-7