【问题标题】:Experimenting with String creation尝试创建字符串
【发布时间】:2013-05-14 01:08:22
【问题描述】:

我在测试字符串创建并检查其哈希码时发现了一个有趣的案例。

在第一种情况下,我使用复制构造函数创建了字符串:

public class Test {

    /**
     * @param args
     */
    public static void main(String[] args) {

        String s1 = new String("myTestString");

        String s3 = s1.intern();

        System.out.println("S1: " + System.identityHashCode(s1) + "  S3:"
                + System.identityHashCode(s3));
    }


}

以上代码的输出为:

S1:816115710 S3:478684581

这是预期的输出,因为实习字符串从字符串池中选择引用,而 s1 选择新对象的引用。所以他们的身份哈希码是不同的。

现在,如果我使用 char 数组创建字符串,那么我会看到一些奇怪的行为:

public class Test {

    /**
     * @param args
     */
    public static void main(String[] args) {

        char[] c1 = { 'm', 'y', 'T', 'e', 's', 't', 'S', 't', 'r', 'i', 'n',
                'g' };

        String s5 = new String(c1);

        String s6 = s5.intern();

        System.out.println("S5: " + System.identityHashCode(s5) + "  S6:"
                + System.identityHashCode(s6));
    }

}

以上代码的输出为:

S5:816115710 S6:816115710

这是一个意外的输出。实习字符串和新字符串对象如何具有相同的identityhashcode??

有什么想法吗?

【问题讨论】:

  • @IgorS.:它与我的问题有何关联?
  • "多个对象可以有相同的身份哈希码。这就是哈希码的本质。"
  • @IgorS.:是的,他们只能在某些情况下拥有。在上述情况下,他们不应该有。
  • 应该的。为了保持低内存使用 - VM 显然使用延迟加载,因为您没有对指向相同内存地址的字符串做任何事情。第一种情况可能不同,因为字符编码或/和字符串结束字符。

标签: java string memory


【解决方案1】:

在第一种情况下,myTestString 文字在您调用intern 之前在池中,而在第二种情况下,您的字符串s5 不在池中直接。

如果我们逐步查看您的示例,会发生以下情况:

  • String s1 = new String("myTestString"); => 使用字符串字面量在池中创建了一个字符串myTestString(我们称之为s0),同时还创建了一个新的字符串s1,它不在池中。
  • String s3 = s1.intern(); => 检查池中是否存在等效字符串并找到s0。现在s3s0 指的是同一个实例(即s3 == s0 为真,但s1 != s0)。

在你的第二个例子中:

  • String s5 = new String(c1); 创建一个新的字符串,它不在池中
  • String s6 = s5.intern(); 检查myTestString 是否在池中但找不到它,因此对intern 的调用会在池中创建一个新字符串reference,该字符串引用与@987654338 相同的字符串@。所以s6 == s5 是真的。

最后你可以运行这两个程序来确认我的解释(第二个打印true 3次):

public static void main(String[] args) {
    String s1 = new String("myTestString");
    String s3 = s1.intern();
    System.out.println("myTestString" == s1);
    System.out.println(s3 == s1);
    System.out.println("myTestString" == s3);
}

public static void main(String[] args) {
    String s1 = new String(new char[] {'m', 'y', 'T', 'e', 's', 't', 'S', 't', 'r', 'i', 'n', 'g'});
    String s3 = s1.intern();
    System.out.println("myTestString" == s3);
    System.out.println("myTestString" == s1);
    System.out.println(s3 == s1);
}

【讨论】:

  • 为什么s5会直接放入pool?我正在使用 new 运算符来创建它。
  • 当您调用实习生时它被放入池中,因为该特定字符串尚未在池中。在这种情况下,您创建字符串的方式无关紧要。
  • 同样也应该适用于 s1, s3 然后。为什么不一样?
  • @lok​​i 我添加了更多细节。不同之处在于,在您的第一个示例中,有一个字符串文字会在您的程序运行之前进入池。
  • +1 好点,没想到解释“预期结果”;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-20
  • 2014-12-09
  • 1970-01-01
  • 2016-04-20
  • 2015-08-07
  • 1970-01-01
相关资源
最近更新 更多