字符串池存储文字还是对象?
Does string pool store literals or objects?
Whosebug 充满了与不同类型的 String 初始化相关的问题。我了解 String s = "word"
与 String s = new String("word")
有何不同。所以没必要'touch'那个话题。
我注意到不同的人提到字符串池存储 constants/objects/literals.
常量 是可以理解的,因为它们是最终的,所以它们总是 'stay' 在那里。是的,SCP.
中也没有存储重复项
但我无法理解 SCP 是否存储 objects 或 literals。它们是完全不同的概念。 对象是一个实体,而文字只是一个值.那么这个问题的正确答案是什么。 SCP 存储的是 objects 还是 literals?我知道不能两者兼得 :)
严格来说,“文字”不是一个值;它是一种句法形式。 Java 中的字符串文字是一个双引号,后跟一些 non-double-quote(或转义双引号)字符,以另一个双引号结尾。 “文字值”是从 source-code 文字创建的值,而不是 a.concat(b)
等评估值。核心区别在于字面值可以在编译时识别,而评估值只能在执行期间获知。这允许编译器将文字值存储在编译后的字节码中。 (由于编译器在编译时也知道由字面值初始化的常量,因此也可以在编译时计算仅使用常量的求值。)
在口语中,可以将文字值称为“文字”,但这可能是您混淆的根源 - 值就是一个值,无论其来源是文字还是评估。
I know it can't be both
文字值和评估值之间的区别不同于对象值和原始值之间的区别。 "foo"
是一个文字字符串值(并且由于字符串是对象,它也是一个对象)。 3
是一个文字原始(整数)值。如果 x
当前为 7
,则 18 - x
的计算结果为 non-literal 原始值 11
。如果 y
当前为 "world!"
,则 "Hello, " + y
的计算结果为 non-literal、non-primitive 值 "Hello, world!"
.
文字 是由"
分隔的源代码 的一大块。例如,在下面的源代码行中:
String s = "Hello World";
"Hello World"
是字符串文字。
对象 是一个有用的抽象,用于有意义的内存位,其中的数据(当组合在一起时)代表某种东西,无论它是 Car
、Person
, 或 String
.
字符串池存储 String
个对象而不是 String
个文字,仅仅是因为 字符串池不存储源代码。
您可能会听到人们说“字符串池存储字符串文字”。他们(可能)并不意味着字符串池以某种方式在其中包含源代码 "Hello World"
。它们(可能)意味着源代码中由字符串文字表示的所有 String
都将放入字符串池中。事实上,源代码中由常量表达式生成的 String
s 也会自动添加到字符串池中。
问得好。通过 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;
}
Whosebug 充满了与不同类型的 String 初始化相关的问题。我了解 String s = "word"
与 String s = new String("word")
有何不同。所以没必要'touch'那个话题。
我注意到不同的人提到字符串池存储 constants/objects/literals.
常量 是可以理解的,因为它们是最终的,所以它们总是 'stay' 在那里。是的,SCP.
中也没有存储重复项但我无法理解 SCP 是否存储 objects 或 literals。它们是完全不同的概念。 对象是一个实体,而文字只是一个值.那么这个问题的正确答案是什么。 SCP 存储的是 objects 还是 literals?我知道不能两者兼得 :)
严格来说,“文字”不是一个值;它是一种句法形式。 Java 中的字符串文字是一个双引号,后跟一些 non-double-quote(或转义双引号)字符,以另一个双引号结尾。 “文字值”是从 source-code 文字创建的值,而不是 a.concat(b)
等评估值。核心区别在于字面值可以在编译时识别,而评估值只能在执行期间获知。这允许编译器将文字值存储在编译后的字节码中。 (由于编译器在编译时也知道由字面值初始化的常量,因此也可以在编译时计算仅使用常量的求值。)
在口语中,可以将文字值称为“文字”,但这可能是您混淆的根源 - 值就是一个值,无论其来源是文字还是评估。
I know it can't be both
文字值和评估值之间的区别不同于对象值和原始值之间的区别。 "foo"
是一个文字字符串值(并且由于字符串是对象,它也是一个对象)。 3
是一个文字原始(整数)值。如果 x
当前为 7
,则 18 - x
的计算结果为 non-literal 原始值 11
。如果 y
当前为 "world!"
,则 "Hello, " + y
的计算结果为 non-literal、non-primitive 值 "Hello, world!"
.
文字 是由"
分隔的源代码 的一大块。例如,在下面的源代码行中:
String s = "Hello World";
"Hello World"
是字符串文字。
对象 是一个有用的抽象,用于有意义的内存位,其中的数据(当组合在一起时)代表某种东西,无论它是 Car
、Person
, 或 String
.
字符串池存储 String
个对象而不是 String
个文字,仅仅是因为 字符串池不存储源代码。
您可能会听到人们说“字符串池存储字符串文字”。他们(可能)并不意味着字符串池以某种方式在其中包含源代码 "Hello World"
。它们(可能)意味着源代码中由字符串文字表示的所有 String
都将放入字符串池中。事实上,源代码中由常量表达式生成的 String
s 也会自动添加到字符串池中。
问得好。通过 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;
}