与String interning相关

Sum*_*rma 18 java string string-interning

public static void main(String[] args) {

    String a = new String("lo").intern();
    final String d = a.intern();
    String b = "lo";
    final String e = "lo";
    String c = "Hello";
    System.out.println(b==a);//true
    System.out.println(d==a);//true
    System.out.println(e==a);//true
    System.out.println(c=="Hel"+a); //why is this false? when e==a is true
    System.out.println(c=="Hel"+d); //why is this false?
    System.out.println(c=="Hel"+b); //why is this false?
    System.out.println(c=="Hel"+e); //this is true

}
Run Code Online (Sandbox Code Playgroud)

这导致了

true
true
true
false
false
false
true
Run Code Online (Sandbox Code Playgroud)

表达式e==a为true意味着相同的引用.那么为什么最后一个表达式是真的但是第四个到最后一个表示c== "Hel"+a是假的?

Boh*_*ian 16

表达方式

"Hel" + a
Run Code Online (Sandbox Code Playgroud)

不是编译时间常量.实际上,它编译为:

new StringBuilder().append("Hel").append(a).toString()
Run Code Online (Sandbox Code Playgroud)

(或类似的)在运行时创建一个新的String对象.

然而,因为e是最后时,编译器可以确定的串联"Hel"e的值是恒定值,所以它实习生.


Iły*_*sov 10

所有这些字符串都是在运行时计算的,这就是它们不同的原因

System.out.println(c=="Hel"+a); //why is this false? when e==a is true
System.out.println(c=="Hel"+d); //why is this false?
System.out.println(c=="Hel"+b); //why is this false?
Run Code Online (Sandbox Code Playgroud)

这个在编译期间计算,因为e是最终的:

System.out.println(c=="Hel"+e); //this is true
Run Code Online (Sandbox Code Playgroud)

如果您将代码更改为:

    System.out.println(c==("Hel"+a).intern()); //why is this false? when e==a is true
    System.out.println(c==("Hel"+d).intern()); //why is this false?
    System.out.println(c==("Hel"+b).intern()); //why is this false?
Run Code Online (Sandbox Code Playgroud)

所有这些都会产生真实的

  • @markspace我没有确切的引用,但是只要e是final,java编译器就会计算常量表达式(在本例中为"Hel"+ e) - 编译器假设这是常量 (2认同)
  • [JLS 3.10.5](http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5):"由常量表达式计算的字符串(§15.28)在编译时计算,然后将它们视为文字." (2认同)

bed*_*rin 5

Java编译器(javac)转换你的Java代码字节码这是由执行JVM.它还为您做了一些优化.您可以使用javap-c参数的实用程序检查生成的字节代码

与最终字符串连接

c==a之所以会如此cfinal 这里是这个片段的字节码(仅去年比较):

public static void main(java.lang.String[]);
  Code:
   0:   ldc     #2; //String Hello
   2:   astore_2
   3:   getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;
   6:   aload_2
   7:   ldc     #2; //String Hello
   9:   if_acmpne       16
   12:  iconst_1
   13:  goto    17
   16:  iconst_0
   17:  invokevirtual   #4; //Method java/io/PrintStream.println:(Z)V
   20:  return

}
Run Code Online (Sandbox Code Playgroud)

如您所见,java编译器已将"Hel"与"lo"合并,只比较两个字符串leterals"Hello".Java默认情况下实习字符串文字 - 这就是它返回true的原因

与非final String连接

如果将字符串文字与非final String变量连接起来,则字节代码将不同:

public static void main(java.lang.String[]);
  Code:
   0:   ldc     #2; //String lo
   2:   astore_1
   3:   ldc     #3; //String Hello
   5:   astore_2
   6:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   9:   aload_2
   10:  new     #5; //class java/lang/StringBuilder
   13:  dup
   14:  invokespecial   #6; //Method java/lang/StringBuilder."<init>":()V
   17:  ldc     #7; //String Hel
   19:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   22:  aload_1
   23:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   26:  invokevirtual   #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   29:  if_acmpne       36
   32:  iconst_1
   33:  goto    37
   36:  iconst_0
   37:  invokevirtual   #10; //Method java/io/PrintStream.println:(Z)V
   40:  return

}
Run Code Online (Sandbox Code Playgroud)

这里我们比较java/lang/StringBuilder.toString:()Ljava/lang/String;显然返回另一个对象的方法的结果- 它等于"Hello"值而不是引用

您可以在此stackoverflow问题中找到有关比较字符串的更多详细信息