字符串池存储字面量还是对象?

huangapple go评论76阅读模式
英文:

Does string pool store literals or objects?

问题

Stackoverflow 充满了与不同类型的字符串初始化相关的问题。我了解 String s = "word"String s = new String("word") 有多么不同。所以不需要涉及那个主题。

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

常量 是可以理解的,因为它们是 final 的,所以它们总是会保留在那里。是的,重复的内容并不会被存储在 字符串池 中。

但我无法理解 字符串池 是否存储 对象 或者 字面量。它们是完全不同的概念。对象实体,而 字面量 只是 一个值。那么对于这个问题,什么才是正确的答案呢?字符串池 到底是存储 对象 还是 字面量?我知道它不可能两者都存储 字符串池存储字面量还是对象?

英文:

Stackoverflow is full of questions related to different types of String initialization. I understand how different is String s = "word" to String s = new String("word"). So no need to 'touch' that topic.

I noticed that different people refer that String pool stores constants/objects/literals.

Constants are understandable, as they are final, so they always 'stay' there. Yes, also duplicates aren't stored in SCP.

But I can't understand does SCP store objects or literals. They are totally different concepts. Object is an entity, while literal is just a value. So what is the correct answer to this. Does SCP store objects or literals? I know it can't be both 字符串池存储字面量还是对象?

答案1

得分: 3

"literal" 在严格意义上并不是一个值;它是一种语法形式。在Java中,字符串字面量是由双引号开始,后面跟着一些非双引号(或经过转义的双引号)字符,以另一个双引号结束。一个 "字面值" 是从源代码字面量创建的值,与诸如 a.concat(b) 这样的求值值相对应。核心区别在于,字面值可以在编译时被确定,而求值值只能在执行期间知道。这使得编译器能够将字面值存储在编译后的字节码中。(由于由字面值初始化的常量在编译时编译器也是已知的,只使用常量的计算也可以在编译时进行。)

在口语中,可以将字面值称为 "字面量",但这可能是你困惑的根源 - 一个值就是一个值,无论其起源是字面量还是求值。

我知道它不能同时是两者

字面值和求值值之间的区别与对象值和基本值之间的区别是不同的。"foo" 是一个字面量字符串值(由于字符串是对象,它也是一个对象)。3 是一个字面量基本(整数)值。如果 x 当前是 7,那么 18 - x 求值为一个非字面量基本值 11。如果 y 当前是 "world!",那么 "Hello, " + y 求值为一个非字面量、非基本值 "Hello, world!"

英文:

Strictly speaking, "literal" is not a value; It is a syntactic form. A String literal in Java is a double quote followed by some non-double-quote (or escaped double quote) characters, ending in another double quote. A "literal value" is a value that is created from a source-code literal, as opposed to an evaluated value such as a.concat(b). The core difference is that the literal value can be identified at compilation time, while an evaluated value can only be known during execution. This allows the compiler to store the literal values inside the compiled bytecode. (Since constants initialised by literal values are also known by the compiler at compile time, evaluations that only use constants can also be computed at compile time.)

In colloquial speech one can refer to a literal value as a "literal", but that may be the source of your confusion - a value is a value, whether its origin is a literal, or an evaluation.

> I know it can't be both

The distinction between a literal value and an evaluated value is separate from a distinction between an object value and a primitive value. "foo" is a literal String value (and since Strings are objects, it is also an object). 3 is a literal primitive (integer) value. If x is currently 7, then 18 - x evaluates to a non-literal primitive value of 11. If y is currently "world!", then "Hello, " + y evaluates to a non-literal, non-primitive value "Hello, world!".

答案2

得分: 3

Literals 是由 " 定界的一段 源代码。例如,在以下这行源代码中:

String s = "Hello World";

"Hello World" 是一个字符串字面量。

对象 是对有意义的内存片段的有用抽象,其中包含的数据(当组合在一起时)表示某个东西,无论是 CarPerson 还是 String

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

你可能会听到人们说“字符串池存储字符串字面量”。他们(很可能)并不是指字符串池里以某种方式含有源代码 "Hello World"。他们(很可能)是指在您的源代码中,由字符串字面量表示的所有 String 将被放入字符串池中。事实上,您的源代码中由常量表达式产生的 String 也会自动添加到字符串池中。

英文:

Literals are a chunk of source code that is delimited by ". For example, in the following line of source code:

String s = "Hello World";

"Hello World" is a string literal.

Objects are a useful abstraction for a meaningful bits of memory with data that (when grouped together) represents something, whether it be a Car, Person, or String.

The string pool stores String objects rather than String literals, simply because the string pool does not store source code.

You might hear people say "the string pool stores string literals". They (probably) don't mean that the string pool somehow has the source code "Hello World" in it. They (probably) mean that all the Strings represented by string literals in your source code will get put into the string pool. In fact, the Strings produced by constant expressions in your source code also gets added to the string pool automatically.

答案3

得分: 2

不错的问题。答案可以通过查看String::intern()的实现方式来找到。根据javadoc的说明:

* 当调用intern方法时,如果字符串池中已经包含一个与该{@code String}对象相等的字符串,比较方式是使用{@link #equals(Object)}方法,那么将返回池中的字符串。否则,将把这个{@code String}对象添加到池中,并返回对这个{@code String}对象的引用。
* <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);

  // 找到
  if (found_string != NULL) {
    ensure_string_alive(found_string);
    return found_string;
  }

  ... ... ...

  Handle string;
  // 尽可能地重用字符串
  if (!string_or_null.is_null()) {
    string = string_or_null;
  } else {
    string = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
  }

... ... ...

  // 在获取the_table()之前获取StringTable_lock,因为在安全点可能会发生更改。
  oop added_or_found;
  {
    MutexLocker ml(StringTable_lock, THREAD);
    // 否则,将符号添加到表中
    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

英文:

Nice question. The answer can be found through how String::intern() was implemented. From 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>

So the String pool stores string object.

We can open the source code to confirm the answer. String::intern() is a native method and it's defined in 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

huangapple
  • 本文由 发表于 2020年10月6日 12:25:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/64219335.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定