JVM对字符串拼接的优化
- 不带变量的字符串拼接
- 带变量的字符串拼接(不是全部final变量)
- 全部final变量字符串拼接
不带变量的字符串拼接
public static void main(String[] args) {String d = "hello" + "world";}
L0LINENUMBER 7 L0LDC "helloworld"ASTORE 1L1
可以看出JVM就直接把计算好的字符串结果执行LDC操作。
带变量的字符串拼接(不是全部final变量)
public static void main(String[] args) {String d = "hello" + "world";d = "hello" + "world" + d;}
LINENUMBER 8 L1NEW java/lang/StringBuilderDUPINVOKESPECIAL java/lang/StringBuilder.<init> ()VLDC "helloworld"INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;ALOAD 1INVOKEVIRTUAL 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;}
L0LINENUMBER 6 L0LDC "hello"ASTORE 1L1LINENUMBER 7 L1LDC "world"ASTORE 2L2LINENUMBER 8 L2LDC "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;}
L0LINENUMBER 6 L0LDC "hello"ASTORE 1L1LINENUMBER 7 L1LDC "world"ASTORE 2L2LINENUMBER 8 L2NEW java/lang/StringBuilderDUPINVOKESPECIAL java/lang/StringBuilder.<init> ()VLDC "hello"INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;ALOAD 2INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;ASTORE 3
能够看到,一样是初始化了一个StringBuilder实例,并使用这个StringBuilder实例进行了字符串拼接操作。