JVM对字符串拼接的优化
不带变量的字符串拼接
public static void main(String[] args) {
String d = "hello" + "world";
}
L0
LINENUMBER 7 L0
LDC "helloworld"
ASTORE 1
L1
可以看出JVM就直接把计算好的字符串结果执行LDC操作。
带变量的字符串拼接(不是全部final变量)
public static void main(String[] args) {
String d = "hello" + "world";
d = "hello" + "world" + d;
}
LINENUMBER 8 L1
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "helloworld"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 1
遇到变量,JVM会初始化一个StringBuilder实例去完成字符串的拼接工作。跟自己像下面代码直接初始化一个StringBuilder实例进行拼接操作是一样的。
d = new StringBuilder().append("hello" + "world").append(d).toString();
全部final变量字符串拼接
public static void main(String[] args) {
final String str1 = "hello";
final String str2 = "world";
String str3 = str1 + str2;
}
L0
LINENUMBER 6 L0
LDC "hello"
ASTORE 1
L1
LINENUMBER 7 L1
LDC "world"
ASTORE 2
L2
LINENUMBER 8 L2
LDC "helloworld"
ASTORE 3
可以看到如果拼接的所有变量都是final变量,这里的操作类似不带变量的字符串拼接。由于中途为每一个子字符串产生了一个final变量,会相较于不带变量的字符串拼接多了LDC把变量数据从常量池入栈的操作,全部子字符串执行完LDC操作后,才会对拼接结果执行LDC操作。
如果拼接的子字符串并不是全部都是final变量,那么这样的操作就会回归到带变量的字符串拼接(不是全部final变量)操作。
public static void main(String[] args) { final String str1 = "hello"; String str2 = "world"; String str3 = str1 + str2; }
L0 LINENUMBER 6 L0 LDC "hello" ASTORE 1 L1 LINENUMBER 7 L1 LDC "world" ASTORE 2 L2 LINENUMBER 8 L2 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 2 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String; ASTORE 3
能够看到,一样是初始化了一个StringBuilder实例,并使用这个StringBuilder实例进行了字符串拼接操作。