当我注意到有关字符串连接的这一点时,我正在查看String
Javadoc:
Java语言为字符串提供特殊支持 连接运算符(+),以及将其他对象转换为 字符串。
String
串联通过实现StringBuilder
(或StringBuffer
)
从Java 8 JLS 15.8.1开始,它是编译器的选择(强调我的):
实现可以选择执行转换和连接 在一步中避免创建然后丢弃中间体 字符串对象。增加重复字符串的性能 串联, Java编译器可以使用StringBuffer类或 类似的技术减少了中间String对象的数量 通过评估表达式创建的。
我做了一个小程序,看看它编译成什么
public class Tester {
public static void main(String[] args) {
System.out.println("hello");
for (int i = 1; i < 5; i++) {
String s = "hi " + i;
System.out.println(s);
}
String t = "me";
for (int i = 1; i < 5; i++) {
t += i;
System.out.println(t);
}
System.out.println(t);
}
}
运行javap -c Tester
时的输出显示正在使用StringBuilder
:
Compiled from "Tester.java"
public class Tester {
public Tester();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String hello
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_1
9: istore_1
10: iload_1
11: iconst_5
12: if_icmpge 48
15: new #5 // class java/lang/StringBuilder
18: dup
19: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
22: ldc #7 // String hi
24: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
27: iload_1
28: invokevirtual #9 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
31: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
34: astore_2
35: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
38: aload_2
39: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
42: iinc 1, 1
45: goto 10
48: ldc #11 // String me
50: astore_1
51: iconst_1
52: istore_2
53: iload_2
54: iconst_5
55: if_icmpge 90
58: new #5 // class java/lang/StringBuilder
61: dup
62: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
65: aload_1
66: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
69: iload_2
70: invokevirtual #9 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
73: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
76: astore_1
77: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
80: aload_1
81: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
84: iinc 2, 1
87: goto 53
90: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
93: aload_1
94: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
97: return
}
我已经查看了一些问题,这些问题告诉StringBuilder
由于StringBuffer
中的同步而导致StringBuilder
通常更快,并且这取代了这些字符串连接:
所以,考虑到我所阅读的内容,StringBuffer
通常是更好的选择,这让我想到了几件事:
StringBuilder
代替AbstractStringBuilder
?答案 0 :(得分:7)
您引用的规范的措辞源于旧规范。简单的答案是,在Java 1.5 aka Java 5之前没有StringBuilder
。因此,较旧的编译器不必在StringBuffer
和StringBuilder
之间进行选择,当时的规范只是建议使用可用的。
使用Java 5,引入了StringBuilder
,它不使用synchronized
方法,这对于String
连接的用例是完美的,因为它是纯粹的本地操作。因此,对于定位1.5
或更高版本的编译器,有一个选择(仍然包含规范的单词“或类似技术”),他们将选择StringBuilder
,因为没有理由使用StringBuffer
1}}定位1.5
或更高时。
答案 1 :(得分:3)
这取决于编译器实现(javac
不是唯一的编译器)。但是,对于StringBuffer
使用StringBuilder
进行这些类型的使用,绝不是一个好例子。它始终是一个使用范围狭窄的对象,StringBuffer
的同步不提供任何功能值。
所以简短的回答是没有编译器/应该/曾经使用StringBuffer
。