是否在运行时字符串中进行了检查?

时间:2018-08-16 05:49:46

标签: java string-interning

这是我的代码:

public class StringExperimenter {
    public static void main(String[] args) {
        String s1 = "This is" + "limafoxtrottango";
        String s2 = "This is" + getName();
        String s3 = "This is" + getName();
        System.out.println(s1 == s2);  // prints false
        System.out.println(s3 == s2);  // prints false
    }

    private static String getName() {
        return "limafoxtrotango";
    }
}

现在,我了解到s1由编译器在编译时进行评估,然后被 interned

但是,s2s3呢?两者都是在运行时上创建的。那么,是否创建了两个不同的字符串?这些字符串会进入常量字符串池吗?

3 个答案:

答案 0 :(得分:4)

s1已被完全拘留,即

This islimafoxtrottango

因为字符串连接发生在编译时

另外两个需要方法调用,仅中间字符串被插入。串联不是这样,因为它发生在运行时

您还已经观察到了,

System.out.println(s1 == s2);    //prints false
System.out.println(s3 == s2);    //prints false

否则将打印true


您可以查看 JLS (Java语言规范)以获取有关此行为的详细信息,每个有效的Java实现都必须完全按照这种方式进行操作。

来自JLS§15.28的有关常量表达式

  

常量表达式是表示原始类型或String的值的表达式,该值不会突然完成,并且仅使用以下内容组成:

以下列表或多或少包含

  
      
  • 文字
  •   
  • 操作员喜欢+
  •   
  • 常量变量
  •   

重要的是,即使它们返回了恒定值,它也不会列出任何方法调用。

它还指出:

  

类型为String的常量表达式总是“ interem ” ,以便使用方法{{ 1}}。

答案 1 :(得分:2)

如果您从命令行这样编译类:

javac.exe -g StringExperimenter.java

然后使用javap.exe -v StringExperimenter.class研究生成的类文件,您将看到生成了以下字节码:

...  
public static void main(java.lang.String...);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC, ACC_VARARGS
    Code:
      stack=3, locals=4, args_size=1
         0: ldc           #2                  // String This islimafoxtrottango
         2: astore_1
         3: new           #3                  // class java/lang/StringBuilder
         6: dup
         7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
        10: ldc           #5                  // String This is
        12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder
        15: invokestatic  #7                  // Method getName:()Ljava/lang/String;
        18: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder
        21: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        24: astore_2
        25: new           #3                  // class java/lang/StringBuilder
        28: dup
        29: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
        32: ldc           #5                  // String This is
        34: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder
        37: invokestatic  #7                  // Method getName:()Ljava/lang/String;
        40: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder
        43: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        46: astore_3
        47: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
        50: aload_1
        51: aload_2
        52: if_acmpne     59
        55: iconst_1
        56: goto          60
        59: iconst_0
        60: invokevirtual #10                 // Method java/io/PrintStream.println:(Z)V
        63: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
        66: aload_3
        67: aload_2
        68: if_acmpne     75
        71: iconst_1
        72: goto          76
        75: iconst_0
        76: invokevirtual #10                 // Method java/io/PrintStream.println:(Z)V
        79: return
...  

基于此,我想说s1是实习生,而s2和s3是在运行时计算的(使用StringBuilder)。

答案 2 :(得分:1)

字符串的含义在Java中是不变的。 以上结果是正确的。 每当我们通过隐式在字符串中追加内容时,都会在String实习生池中创建一个新引用。

因此,如果使用 equals 方法比较以上三个字符串,则返回True,但如果使用 == 运算符进行比较,则返回false。