以下内容基于jdk1.8
测试代码
public static void main(String[] args) {
String a = "a";
for (int i = 0; i < 100; i++) {
a += "a";
}
}
字节码
public static main([Ljava/lang/String;)V
// parameter args
L0
LINENUMBER 6 L0
LDC "a"
ASTORE 1
L1
LINENUMBER 7 L1
ICONST_0
ISTORE 2
L2
FRAME APPEND [java/lang/String I]
ILOAD 2
BIPUSH 100
IF_ICMPGE L3
L4
LINENUMBER 8 L4
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "a"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 1
L5
LINENUMBER 7 L5
IINC 2 1
GOTO L2
L3
LINENUMBER 10 L3
FRAME CHOP 1
RETURN
L6
LOCALVARIABLE i I L2 L3 2
LOCALVARIABLE args [Ljava/lang/String; L0 L6 0
LOCALVARIABLE a Ljava/lang/String; L1 L6 1
MAXSTACK = 2
MAXLOCALS = 3
从字节码中可以看到,在循环中,每次+都new 了一个StringBuilder,频繁的创建销毁对象会导致大量的开销,所以在拼接字符串的时候推荐直接使用StringBuilder,在需要线程安全的时候使用StringBuffer
不过也有例外,针对下面的情况
public static void main(String[] args) {
String a = "a" + "b" + "c";
}
字节码
public static main([Ljava/lang/String;)V
// parameter args
L0
LINENUMBER 6 L0
LDC "abc"
ASTORE 1
L1
LINENUMBER 7 L1
RETURN
L2
LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
LOCALVARIABLE a Ljava/lang/String; L1 L2 1
MAXSTACK = 1
MAXLOCALS = 2
可以看到虽然代码里用两个+ 但是字节码中并没有任何StringBuilder创建出来,jdk针对创建字符串同一行代码里的+进行了优化,所以如果单行创建字符串可以安心使用+,而不必在创建一个StringBuilder