如果Java编译器出现在变量之后,为什么不连接字符串文字呢?

时间:2015-02-25 22:08:15

标签: java

我有以下测试代码:

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编译的。

3 个答案:

答案 0 :(得分:16)

因为the string concatenation operator (+) is syntactically left associative

  

例如,表达式:

a + b + c
     

总是被视为含义:

(a + b) + c

不可否认,如果bc是字符串,则表达式等同于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编译器可以在内部应用优化,因为它不会改变可观察的语义。