我知道Javac编译器能够使用+
/ StringBuilder
转换字符串连接StringBuffer
,我很想知道从哪个版本开始引入了这个变化吗?
我正在使用此示例代码:
public class Main {
public static void main(String[] args) {
String a = args[0];
String s = "a";
s = s + a;
s = s + "b";
s = s + "c";
s = s + "d";
s = s + "e";
System.out.println(s);
}
}
到目前为止,我已尝试使用javac 1.8.0_121
,javac 1.6.0_20
,javac 1.5.0_22
和java 1.4.2_19
。
以下是我在javap -c
使用1.4.2_19
时看到的字节码示例:
6: astore_2
7: new #3; //class StringBuffer
10: dup
11: invokespecial #4; //Method java/lang/StringBuffer."<init>":()V
14: aload_2
15: invokevirtual #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
18: aload_1
19: invokevirtual #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
22: invokevirtual #6; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
所有4个版本似乎都在使用StringBuilder / StringBuffer优化,所以我很想知道从哪个Javac版本开始引入了这个更改?
答案 0 :(得分:31)
以下是language specification from version 1:
的引用实现可以选择在一个步骤中执行转换和连接,以避免创建然后丢弃中间
String
对象。为了提高重复字符串连接的性能,Java编译器可以使用StringBuffer
类(第20.13节)或类似技术来减少通过表达式求值创建的中间String
对象的数量。
当时回来,他们有StringBuffer
而不是StringBuilder
。
还引用了JDK1.0.2的StringBuffer
:
此类是字符的可扩展缓冲区。它主要用于创建字符串。编译器使用它来实现“+”运算符。
答案 1 :(得分:11)
我查阅了Java语言规范,第一版(从1996年开始)。不容易找到,但是here it is。连接优化的过程即便如此:
实现可以选择在一个步骤中执行转换和连接,以避免创建然后丢弃中间String对象。为了提高重复字符串连接的性能,Java编译器可以使用StringBuffer类(第20.13节)或类似技术来减少通过表达式求值创建的中间String对象的数量。
该规范当时属于StringBuffer
,但StringBuilder
(当前JLS措辞所指的)可能被视为性能更好,因为其方法不同步。
然而,这并不意味着人们应该依赖优化,因为总是到位。例如,循环中的字符串连接不会得到优化。
答案 2 :(得分:5)
JLS已经在一些答案中给出了。我只是想说明StringBuffer(https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html)是从1.0开始的,而
StringBuilder(https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)来自1.5版本。请参阅相应javadoc的since:
部分。
答案 3 :(得分:5)
这不回答问题,但我只想补充一点,即在jdk-9中int
是允许的策略之一,但不是默认值。
StringBuilder::append
它实际上是字符串连接的private enum Strategy {
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder}.
*/
BC_SB,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but trying to estimate the required storage.
*/
BC_SB_SIZED,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but computing the required storage exactly.
*/
BC_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also tries to estimate the required storage.
*/
MH_SB_SIZED,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also estimate the required storage exactly.
*/
MH_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that constructs its own byte[] array from
* the arguments. It computes the required storage exactly.
*/
MH_INLINE_SIZED_EXACT
}
字节码,因此它的实现现在是JRE特定的,而不是编译器。默认策略btw是:invokedynamic