在修改字符串后进行字符串池化

3
我有这段代码
String a="test";
String b="test";
if(a==b)
   System.out.println("a == b");
else
   System.out.println("Not True");

每个Java专家都知道这里的if(a==b)会通过,因为有字符串池的存在。
根据字符串池的机制:
每次代码创建字符串文字时,JVM首先检查字符串文字池。如果池中已经存在该字符串,则返回对该实例的引用。如果在池中不存在该字符串,则创建一个新的String对象并将其放置在池中。JVM在此池中最多保留任何String对象的一个副本。字符串文字始终引用字符串池中的对象。
这就是为什么上面的代码中条件语句能够通过的原因。
现在问题来了。在上述代码中当我添加两行额外的代码 a+="1"b+="1" 时,现在字符串a和b的值将是Test1
新的代码如下:

String a="test";
    String b="test";
    if(a==b)
        System.out.println("a == b");
    else
        System.out.println("Not True");
        a+="1"; //it would be test1 now
        b+="1"; //it would also be test1 now
    if(a==b)
       System.out.println("a == b");
    else
      System.out.println("Not True");

现在,在修改了字符串后,当我放置了if(a==b)检查时,它没有通过。我知道这是由于String的不可变特性造成的,但我想知道:

1) 修改后,JVM是否将它们存储为两个不同的对象?
2) JVM是否对任何字符串的修改调用new String()
3) 为什么尽管我在修改时尝试调用intern(),它们仍然不引用为单个对象?
提示:
a+="1".intern();
b+="1".intern();

1
@ThomasW 如果即使得到了如此详细的解释,你仍然持有这种想法,那么我真的希望为你的想法祈祷。 - Freak
3个回答

1

由于字符串是不可变的。在修改字符串后,您的变量现在将引用一个不同的String

创建new String时,如果值在编译时未知,则JVM使用StringBuilder;否则,使用标准的String构造函数。

当添加"1".intern()时,.intern()应用于"1"(而不是a + "1"); 连接会产生新的String对象(而不是字面量),因此ab不引用相同的对象。请记住,当通过new运算符创建Strings时,强制分配新内存。

为了使ab实际引用相同的对象,您必须在两者上调用.intern()

_a = _a.intern(); //adds _a to the String pool
_b = _b.intern(); //makes _b point to the same object as _a, since _b.equals(_a)

1
这是因为当你使用'+='时,由于字符串的不可变性,在堆上创建了一个新的对象而不是在字符串池中创建。如果你想要它在字符串池中,则需要在两个字符串上再次调用intern()方法。
String a="test";
    String b="test";
    if(a==b)
        System.out.println("a == b");
    else
        System.out.println("Not True");
        a+="1"; //it would be test1 now
        b+="1"; //it would also be test1 now

       a=a.intern();
       b=b.intern();

    if(a==b)
       System.out.println("a == b");
    else
      System.out.println("Not True");

现在它将在两种情况下生成'a == b'。有关字符串池的更多信息,请访问此链接

1

1)是的,这就是为什么a == b失败的原因。这些新字符串不是字符串池的一部分,因为它们不是从一开始就是字面量。

2)正如@LuiggiMendoza指出的,如果编译器知道字符串的值,它会使用String构造函数,否则它会在内部使用StringBuilder(最终它将使用String构造函数来返回最终的String)

3)即使“1”是一个字面量,a + "1".intern();的结果本身也不是字面量,而是使用String构造函数创建的新String对象,因此它不会被添加到字符串池中。


对于第二点,只有在“字符串”值可以在编译时确定的情况下才是真的。 - Luiggi Mendoza
@LuiggiMendoza,如果这不是众所周知的呢? - Freak
@morgano请澄清第三点。实际上,我想知道为什么intern()无法将它们放入字符串池中? - Freak
@freak 然后它将创建一个新的 String 对象。 - Luiggi Mendoza
1
@freak,我尽可能澄清了第三点,问题在于在(String a =“x”; String b =“y”; String c = a + b)中,A和B包含文字,但C(“xy”)从未是文字,它是在运行时构建的。 - morgano
@freak 请看我的回复,或许能有所帮助。 - Steve P.

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