【问题标题】:String Constant Pool字符串常量池
【发布时间】:2012-12-18 12:10:11
【问题描述】:

正如这些 Stackoverflow 问题中所解释的:question 1question 2 我知道“字符串文字”是 interned 时:

String s = "abc"; 

JVM 将创建一个新的字符串对象,而不是使用字符串池中的现有对象:

String s = new String("abc");

但是,在阅读了以下两个类似的陈述后,我有一个疑问。

当编译器遇到字符串字面量时,它会检查池以查看是否已经存在相同的字符串。如果找到匹配项,则对新字面量的引用将定向到现有字符串,并且不会创建新的字符串字面量对象。

在这种情况下,由于关键字“new”,我们实际上最终会得到稍微不同的行为。在这种情况下,对 String 字面量的引用仍被放入常量表(String Literal Pool)中,但是,当您遇到关键字“new”时,JVM 必须在运行时创建一个新的 String 对象,而不是使用常量表中的那个。

因此,如果我们在使用“new”并基于上述定义创建对象时,也将引用放在非池内存中AND 到池内存中。 当我们这样做时,JVM 不应该也返回相同的引用吗?

String one = new String("test");
String two = "test";

System.out.println(one.equals(two)); // true
System.out.println(one == two);      // false

因为在声明字符串字面量String three = "test"; 时它已经存在于池中?因此应该返回相同的引用并打印 true?或者前面的语句是否意味着它们将被放入池内存中,但在使用 new 运算符时被简单地跳过?

【问题讨论】:

  • 如果有帮助,只需添加 System.out.println(one.intern() == two); 将返回 true。

标签: java string


【解决方案1】:

也许这会帮助你理解:

String literal = "test";
String one = new String(literal);
String two = "test";

System.out.println(literal == two); //true
System.out.println(one == two); //false

在您发布的示例中:

String one = new String("test");
String two = "test";

由于实习,传递给构造函数String(String) 的引用与引用two 具有相同的值。但是,字符串本身(由这两个引用引用)用于构造一个 new 对象,该对象被分配给引用 one

在这个例子中,恰好有两个Strings 使用值“test”创建:一个在常量池中维护并在您在表达式中使用文字"test" 时引用,第二个由“新”运算符并分配给引用one

编辑

也许你对这个说法感到困惑:

当编译器遇到字符串字面量时,它会检查池中是否已经存在相同的字符串。

请注意,这可能更清楚地表述为:

当编译器遇到字符串字面量时,它会检查池中是否已经存在相同的字符串

字符串仅在显式实习或通过类使用文字时才放入池中。因此,例如,如果您有这种情况:

String te = "te";
String st = "st";

String test = new String(te) + new String(st);

然后,虽然String存在,其值为test,但该字符串将不存在在池中,因为文字"test" 从未出现过。

【讨论】:

  • 这并没有说明堆内存! ://
  • @AnandVarkeyPhilips:这个问题也没有。如果您有相关问题,请随时发布。
  • 嗨@Mark,你能告诉我当使用新操作符创建“测试”时,什么时候会在哪里创建?如果我添加新问题,它可能会被标记为重复。这就是为什么..
【解决方案2】:

"abc" 将一个对象放入常量池,在编译/类加载时new String() 创建一个新对象,在执行时。 所以new String("abc") 两者都有,但在不同的阶段。

【讨论】:

    【解决方案3】:
        //Creates a new object even if one exists in the pool
        String s1 = new String("Tendulkar");
    
        // makes a new object string and then the reference is available to the pool
        String s2 = s1.intern();
    
        //this object is not created but references the address present in the pool
        String s3 = "Tendulkar";
    
        System.out.print(s1==s2); // results in false
        System.out.print(s2==s3); //very very true !!!
    

    【讨论】:

      【解决方案4】:

      你的问题:

      因此,如果我们在使用“new”并基于上述定义创建对象时,还将引用放入非池内存和池内存中。当我们这样做时,JVM不应该也返回相同的引用吗?:

      Ans : 当你使用 new 关键字创建一个新的字符串对象时,生成的地址将是一个堆地址,而不是一个字符串常量池地址。而且两个地址都不一样。

      问题

      String one = new String("test");
      String two = "test";
      
      System.out.println(one.equals(two)); // true
      System.out.println(one == two);      // false
      

      前面的语句是否意味着它们将被放入池内存但在使用新运算符时只是跳过?

      答案:是的,您的假设是正确的。当程序员使用 new 关键字时,JVM 将简单地忽略字符串常量池,并在堆中创建一个新副本。因此两个地址都不一样。

      【讨论】:

        【解决方案5】:

        字符串文字的创建

        1. 每次创建字符串文字时,JVM 都会检查 首先是字符串常量池

        2. 如果字符串已经存在于池中,则引用 返回池中的实例

        3. 如果池中不存在字符串,则创建一个新字符串 实例被创建并放置在池中

        例子,

            String s1 = "Welcome";
            String s2 = "Welcome"; //will not create new instance
        

        字符串文字和字符串对象

            String str1 = "Hello World!!";
            String str2 = "Hello World!!";
            System.out.println(str1 == str2);// true
        

        当创建字符串字面量 str2 时,字符串 “Hello World”不会再次创建。相反,它是 str1 字符串被重用,因为它已经存在于字符串中 常量池。

        因为 str1 和 str2 指的是同一个

            String str3 = new String("Hello World!!");
            String str4 = new String("Hello World!!");
            System.out.println(str3 == str4); // false
        

        在这种情况下,会创建新的 String 对象并 分别由 str3 和 str4 引用。因此,str3 == str4 是假的。 池中的字符串,str1 == str2为真。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-06-08
          • 1970-01-01
          • 2014-09-14
          • 2011-07-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多