String\”+\”拼接底层实现原理

String:常量,不可变,不适合用来字符串拼接,每次都是新创建的对象,消耗较大。
StringBuffer:适合用来作字符串拼接
StringBuilder:JDK1.5引入,适合用来作字符串拼接,与StringBuffer区别是他不是线程安全的

接下来进入正题String”+”拼接底层实现原理

1
2
3
4
5
6
7
8
public class StringDemo01 {

    public static void main(String[] args) {
        String a = "abc";
        String b = "def";
        System.out.println("abcdef" == a+b);
    }
}

通过javap命令分析java汇编指令可以得知底层使用了StringBuilder实现

1
javap -v StringDemo.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
Classfile /home/qiao/桌面/课程/spring_study/java_study/spring_cloud_demo/java_demo/src/main/java/string/StringDemo01.class
  Last modified 2020-6-6; size 730 bytes
  MD5 checksum 8847314e26430be9703f9490a6d8ecf3
  Compiled from "StringDemo01.java"
public class string.StringDemo01
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #12.#25        // java/lang/Object."<init>":()V
   #2 = String             #26            // abc
   #3 = String             #27            // def
   #4 = Fieldref           #28.#29        // java/lang/System.out:Ljava/io/PrintStream;
   #5 = String             #30            // abcdef
   #6 = Class              #31            // java/lang/StringBuilder
   #7 = Methodref          #6.#25         // java/lang/StringBuilder."<init>":()V
   #8 = Methodref          #6.#32         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #9 = Methodref          #6.#33         // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #10 = Methodref          #34.#35        // java/io/PrintStream.println:(Z)V
  #11 = Class              #36            // string/StringDemo01
  #12 = Class              #37            // java/lang/Object
  #13 = Utf8               <init>
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               StackMapTable
  #20 = Class              #38            // "[Ljava/lang/String;"
  #21 = Class              #39            // java/lang/String
  #22 = Class              #40            // java/io/PrintStream
  #23 = Utf8               SourceFile
  #24 = Utf8               StringDemo01.java
  #25 = NameAndType        #13:#14        // "<init>":()V
  #26 = Utf8               abc
  #27 = Utf8               def
  #28 = Class              #41            // java/lang/System
  #29 = NameAndType        #42:#43        // out:Ljava/io/PrintStream;
  #30 = Utf8               abcdef
  #31 = Utf8               java/lang/StringBuilder
  #32 = NameAndType        #44:#45        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #33 = NameAndType        #46:#47        // toString:()Ljava/lang/String;
  #34 = Class              #40            // java/io/PrintStream
  #35 = NameAndType        #48:#49        // println:(Z)V
  #36 = Utf8               string/StringDemo01
  #37 = Utf8               java/lang/Object
  #38 = Utf8               [Ljava/lang/String;
  #39 = Utf8               java/lang/String
  #40 = Utf8               java/io/PrintStream
  #41 = Utf8               java/lang/System
  #42 = Utf8               out
  #43 = Utf8               Ljava/io/PrintStream;
  #44 = Utf8               append
  #45 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #46 = Utf8               toString
  #47 = Utf8               ()Ljava/lang/String;
  #48 = Utf8               println
  #49 = Utf8               (Z)V
{
  public string.StringDemo01();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 11: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=3, args_size=1
         0: ldc           #2                  // String abc
         2: astore_1
         3: ldc           #3                  // String def
         5: astore_2
         6: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
         9: ldc           #5                  // String abcdef
        11: new           #6                  // class java/lang/StringBuilder
        14: dup
        15: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
        18: aload_1
        19: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        22: aload_2
        23: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        26: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        29: if_acmpne     36
        32: iconst_1
        33: goto          37
        36: iconst_0
        37: invokevirtual #10                 // Method java/io/PrintStream.println:(Z)V
        40: return
      LineNumberTable:
        line 14: 0
        line 15: 3
        line 17: 6
        line 21: 40
      StackMapTable: number_of_entries = 2
        frame_type = 255 /* full_frame */
          offset_delta = 36
          locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String ]
          stack = [ class java/io/PrintStream ]
        frame_type = 255 /* full_frame */
          offset_delta = 0
          locals = [ class "[Ljava/lang/String;", class java/lang/String, class java/lang/String ]
          stack = [ class java/io/PrintStream, int ]
}
SourceFile: "StringDemo01.java"

String拼接,有字符串变量参与时,中间会产生StringBuilder对象(JDK1.5之前产生StringBuffer)

字符串拼接原理:运行时, 两个字符串str1, str2的拼接首先会调用 String.valueOf(obj),这个Obj为str1,而String.valueOf(Obj)中的实现是return obj == null ? “null” : obj.toString(), 然后产生StringBuilder, 调用的StringBuilder(str1)构造方法, 把StringBuilder初始化,长度为str1.length()+16,并且调用append(str1)! 接下来调用StringBuilder.append(str2), 把第二个字符串拼接进去, 然后调用StringBuilder.toString返回结果!

StringBuilder(str) 底层调用

1
2
3
4
5
6
7
8
9
10
11
   /**
     * Constructs a string builder initialized to the contents of the
     * specified string. The initial capacity of the string builder is
     * {@code 16} plus the length of the string argument.
     *
     * @param   str   the initial contents of the buffer.
     */
    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }

StringBuilder.toString 底层调用

1
2
3
4
5
    @Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }

Links

https://blog.csdn.net/qq_36771269/article/details/80818200