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