【问题标题】:Does string pool store literals or objects?字符串池是否存储文字或对象?
【发布时间】:2021-01-20 22:50:16
【问题描述】:

Stackoverflow 充满了与不同类型的字符串初始化相关的问题。我了解String s = "word"String s = new String("word") 的不同之处。所以没有必要“触及”那个话题。

我注意到不同的人提到字符串池存储常量/对象/文字

常量是可以理解的,因为它们是最终的,所以它们总是“停留”在那里。是的,SCP 中也不存储重复项。

但我不明白 SCP 是否存储 objectsliterals。它们是完全不同的概念。 Object一个实体,而 literal一个值。那么这个问题的正确答案是什么。 SCP 是否存储对象文字?我知道不可能两者兼有:)

【问题讨论】:

    标签: java string object string-pool string-constant


    【解决方案1】:

    好问题。答案可以通过 String::intern() 的实现方式找到。来自 javadoc:

    * When the intern method is invoked, if the pool already contains a
     * string equal to this {@code String} object as determined by
     * the {@link #equals(Object)} method, then the string from the pool is
     * returned. Otherwise, this {@code String} object is added to the
     * pool and a reference to this {@code String} object is returned.
     * <p>
    

    所以字符串池存储字符串对象。

    我们可以打开源代码来确认答案。 String::intern() 是一个本地方法,定义在 StringTable::intern(), symbolTable.hpp

    oop StringTable::intern(Handle string_or_null, jchar* name,
                        int len, TRAPS) {
      unsigned int hashValue = hash_string(name, len);
      int index = the_table()->hash_to_index(hashValue);
      oop found_string = the_table()->lookup(index, name, len, hashValue);
    
      // Found
      if (found_string != NULL) {
        ensure_string_alive(found_string);
        return found_string;
      }
    
      ... ...
    
      Handle string;
      // try to reuse the string if possible
      if (!string_or_null.is_null()) {
        string = string_or_null;
      } else {
        string = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
      }
    
    ... ...
    
      // Grab the StringTable_lock before getting the_table() because it could
      // change at safepoint.
      oop added_or_found;
      {
        MutexLocker ml(StringTable_lock, THREAD);
        // Otherwise, add to symbol to table
        added_or_found = the_table()->basic_add(index, string, name, len,
                                  hashValue, CHECK_NULL);
      }
    
      ensure_string_alive(added_or_found);
    
      return added_or_found;
    }
    

    http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/f3108e56b502/src/share/vm/classfile/symbolTable.cpp

    【讨论】:

    • 解开了我的疑惑。因此,如果我的池中有 100 个对象,而我要使用add 新对象,那么它会在池中的所有 100 个对象中使用obj1.equals() 来查看它是否存在?对不起,我喜欢仔细检查:)
    • 如果您关心的是效率,那么该代码 sn-p 也可以解决这个问题。它的实现为 HashTable
    【解决方案2】:

    严格来说,“literal”并不是一个值;它是一种句法形式。 Java 中的字符串文字是一个双引号,后跟一些非双引号(或转义的双引号)字符,以另一个双引号结尾。 “文字值”是从源代码文字创建的值,而不是像a.concat(b) 这样的评估值。核心区别在于字面值可以在编译时识别,而评估值只能在执行期间知道。这允许编译器将文字值存储在编译后的字节码中。 (由于在编译时编译器也知道由字面值初始化的常量,因此也可以在编译时计算仅使用常量的计算。)

    在口语中,人们可以将文字值称为“文字”,但这可能是您混淆的根源 - 值就是值,无论其起源是文字还是评估。

    我知道不可能两者兼得

    文字值和评估值之间的区别与对象值和原始值之间的区别是分开的。 "foo" 是一个字符串字面值(因为字符串是对象,所以它也是一个对象)。 3 是文字原始(整数)值。如果x 当前为7,则18 - x 的计算结果为非文字原始值11。如果y 当前为"world!",则"Hello, " + y 的计算结果为非文字、非原始值"Hello, world!"

    【讨论】:

    • 谢谢,除此之外,我还找到了另一个来源“人们使用”。有时他们将“向池中添加对象”称为“添加值”。可能会让初学者感到困惑。
    【解决方案3】:

    文字 是由" 分隔的源代码 块。例如,在以下源代码行中:

    String s = "Hello World";
    

    "Hello World" 是字符串文字。

    对象是对有意义的内存位的有用抽象,其数据(当组合在一起时)代表某物,无论是CarPerson 还是String

    字符串池存储String 对象而不是String 文字,仅仅是因为字符串池不存储源代码

    您可能会听到人们说“字符串池存储字符串文字”。他们(可能)并不意味着字符串池以某种方式包含源代码"Hello World"。它们(可能)意味着源代码中由字符串文字表示的所有Strings 都将被放入字符串池中。事实上,源代码中常量表达式产生的Strings 也会自动添加到字符串池中。

    【讨论】:

    • 老实说,这是有道理的。这是否意味着当我执行String s = new String("hello world") 时,我将得到 2 个完全相同的对象(1 个在堆中,1 个在 SCP 中)?查看它们的结构,而不是它们在 Java 中的工作方式。
    • 是的,您将获得两个被.equals 视为相同的对象。 “关注它们的结构而不是它们在 Java 中的工作方式”是什么意思?
    • 我应该更好地提出这个问题 :) 我的意思是它们具有与任何对象完全相同的特征?因为(在我看来)用 1 个语句存储 2 个相同的对象是没有意义的。并且使用 new 进行字符串创建永远不会检查池,那么为什么不需要在那里添加对象呢?
    • 因为这是您明确要求的。 Java 不判断。如果你不想要两个单独的对象,你就不会做类似String s = new String("hello world") 的事情,而是String s = "hello world"
    • 首先,它们存储在不同的位置,因此它们是“不同的对象”。他们也会有不同的System.identityHashCode。对于您的最后 2 个问题,请查看this
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-01
    • 1970-01-01
    相关资源
    最近更新 更多