常量池中两个字符串的引用ID

4

请访问Java中的字符串常量池

public class StringLiterals {
    public static void main(String[] args) {
        String s1="This is ";
        s1=s1+"my book";
        String s2="This is my book";
        System.out.println(s1==s2);

    }
}

输出结果:False

期望输出结果:True


4
“这是”加上“我的书”首先变成了“这是我的书”,因为缺少一个空格,所以无论如何比较都不相等。 - zapl
"This is " + "my book" 也会返回 false。 - Barnwal Vivek
提供链接后,您真的应该写一个实际的问题来澄清所有这些混乱。 - takendarkk
5个回答

6
也许这可以帮助你更清楚地理解事情。
    String s1 = "This is";
    s1 = s1 + " my book"; // Note the space
    String s2 = "This is my book";
    String s3 = "This is my book";
    System.out.println(s1==s2); // False
    System.out.println(s2==s3); // True

“只有当字符串被显式或由类使用字面量放入池中时,才会将它们放入池中。” 因此,您不能使用 + 运算符连接字符串并期望将其放入字符串常量池中。

走了!有人访问了链接! - takendarkk
1
并不完全正确。将两个常量连接起来会得到一个常量。 - Tom Hawtin - tackline
@TomHawtin-tackline,你能更好地解释一下吗? - Christian Tapia

3
你的代码编译后会生成:
  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16                 // String This is 
       2: astore_1      
       3: new           #18                 // class java/lang/StringBuilder
       6: dup           
       7: aload_1       
       8: invokestatic  #20                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
      11: invokespecial #26                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      14: ldc           #29                 // String my book
      16: invokevirtual #31                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #35                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_1      
      23: ldc           #39                 // String This is my book
      25: astore_2      
      26: getstatic     #41                 // Field java/lang/System.out:Ljava/io/PrintStream;
      29: aload_1       
      30: aload_2       
      31: if_acmpne     38
      34: iconst_1      
      35: goto          39
      38: iconst_0      
      39: invokevirtual #47                 // Method java/io/PrintStream.println:(Z)V
      42: return   

这相当于

public static void main(String[] args) {
    StringBuilder sb = new StringBuilder("This is ");
    sb.append("my book");
    String s1 = sb.toString();
    String s2 = "This is my book";
    System.out.println(s1 == s2);
}

因为。
s1=s1+"my book";

不是一个常量表达式 - 您正在读取变量的值,编译器会假设您在此期间可能已经更改了它。如果您希望

通过常量表达式(§15.28)计算的字符串在编译时计算,然后被视为字面值。 JLS (§3.10.5)

适用于您需要更改代码为

public static void main(String[] args) {
    String s1 = "This is " + "my book";
    String s2 = "This is my book";
    System.out.println(s1 == s2);
}

或者

public static void main(String[] args) {
    final String s1a = "This is ";
    final String s1b = "my book";
    String s1 = s1a + s1b;

    String s2 = "This is my book";
    System.out.println(s1 == s2);
}

现在你可以确保它能正常工作。第二个示例编译为:
  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16                 // String This is 
       2: astore_1      
       3: ldc           #18                 // String my book
       5: astore_2      
       6: ldc           #20                 // String This is my book
       8: astore_3      
       9: ldc           #20                 // String This is my book
      11: astore        4
      13: getstatic     #22                 // Field java/lang/System.out:Ljava/io/PrintStream;
      16: aload_3       
      17: aload         4
      19: if_acmpne     26
      22: iconst_1      
      23: goto          27
      26: iconst_0      
      27: invokevirtual #28                 // Method java/io/PrintStream.println:(Z)V
      30: return    

您可以看到,字符串#20被加载了两次。


2
首先,你漏了一个空格。我猜这只是个错误。
你可能见过类似这样的东西:
"This is"+" my book" == "This is my book"

为什么这有效?因为它全部是编译时常量(compile-time constants)JLS 7 15.28。特别地,指"类型为String的字面量"和"加法和减法操作符+和-"。
还有"简单名称[...]指代常量变量"。但由于你的变量不是final的,所以这并不适用。
但这并不是你必须知道的东西。只要在字符串(String)中使用equals即可。

0

你不能使用 == 来比较两个字符串,因为 == 运算符断言 s1 和 s2 指向同一 内存位置,而不是内容相等。要比较两个字符串的内容是否相同,请使用 String 的 .equals() 方法。另外,在 s1=s1+ 行需要多加一个空格。

代码:

{
public class StringLiterals {
public static void main(String[] args) {
    String s1="This is";
    s1=s1+" my book";
    String s2="This is my book";
    System.out.println(s1.equals(s2));

    }
}

如果你想使用 ==,那么你就必须使用这个:
public class StringLiterals
{
  public static void main(String[] args)
  {
    String s1 = "This is my book";
    String s2 = s1;
    System.out.println(s1 == s2);
  }
}

因为 字符串 是对象,它们的 == 操作与 int、char 和其他原始类型不同。

2
他原本期望它们在同一内存位置。 - Wayne
编译器将连接字符串字面量并对其进行内部化,然后它们就可以正常工作了。http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5 - zapl
我修改了我的答案,展示了一种同时使用.equals()和==的方法,两者都返回true。 - Mike Koch
1
我认为这与隐式 OP 的问题无关。 - Christian Tapia
你修改的答案虽然正确,但并未解决提问者的问题。 - PM 77-1

-1

存在 + 运算符会导致新的字符串。在这里,s1 = s1 + " my book",s1+ " my book " 隐式地创建了新的字符串并将其引用存储到 s1 中。因此,它与 s2 不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接