我有以下测试代码:
public class StringLiteralTest {
static void testPrefix() {
int i = 0;
String prefixConcat = "a" + "b" + i;
}
static void testSuffix() {
int i = 0;
String suffixConcat = i + "c" + "d";
}
}
生成的字节码是:
Compiled from "StringLiteralTest.java"
public class StringLiteralTest {
public StringLiteralTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
static void testPrefix();
Code:
0: iconst_0
1: istore_0
2: new #15 // class java/lang/StringBuilder
5: dup
6: ldc #17 // String ab
8: invokespecial #19 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
11: iload_0
12: invokevirtual #22 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
15: invokevirtual #26 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
18: astore_1
19: return
static void testSuffix();
Code:
0: iconst_0
1: istore_0
2: new #15 // class java/lang/StringBuilder
5: dup
6: iload_0
7: invokestatic #35 // Method java/lang/String.valueOf:(I)Ljava/lang/String;
10: invokespecial #19 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
13: ldc #41 // String c
15: invokevirtual #43 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
18: ldc #46 // String d
20: invokevirtual #43 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: invokevirtual #26 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
26: astore_1
27: return
}
在testPrefix()
中,Java编译器将表达式"a" + "b"
合并到字符串文字"ab"
中,但在testSuffix()
中,表达式"c" + "d"
不是在编译时合并。
为什么编译器不能在第二种方法中组合String文字?
源文件是使用默认的Oracle JDK 8 javac编译的。
答案 0 :(得分:16)
因为the string concatenation operator (+) is syntactically left associative:
例如,表达式:
a + b + c
总是被视为含义:
(a + b) + c
不可否认,如果b
和c
是字符串,则表达式等同于a + (b + c)
。因此,编译器可以在特定情况下执行您建议的 ,但规范并未规定...
答案 1 :(得分:2)
这不是一个好的答案。
定义了添加顺序,并从左侧开始。
此:
public static void main (String[] args)
{
String x= "X" + 1 + 2;
String y= 1 + 2 + "Y";
System.out.println(x);
System.out.println(y);
}
预期输出
X12
3Y
所以我猜测编译器发现文字加文字可以优化为'long literal',但是不能识别重新排序操作会产生相同的结果,因此产生了详细的代码。
答案 2 :(得分:2)
String suffixConcat = i + "c" + "d";
相当于
String suffixConcat = (i + "c") + "d";
你可以说它等同于这个表达式
String suffixConcat = i + ("c" + "d");
将优化为
String suffixConcat = i + "cd";
我认为,这就是为什么字节码不包含优化的原因在Language specification (15.18.1. String Concatenation Operator +)中:
String对象是新创建的(第12.5节),除非表达式是常量表达式(第15.28节)。
换句话说,(i + "c")
必须是新字符串,而(i + "c") + "d"
必须是新字符串。
但是,JIT编译器可以在内部应用优化,因为它不会改变可观察的语义。