这几天我一直在尝试理解String常量池和inter的概念,看了很多文章后我了解了其中的一些部分,但仍然对一些事情感到困惑:-
1.String a = "abc"
这会在字符串常量池中创建一个对象
但是下面这行代码是否在字符串常量池中创建了对象“xyz”?
String b = ("xyz").toLowerCase()
2.
String c = "qwe"
String d = c.substring(1)
d.intern()
String e = "we"
是否应该在类加载期间将文字“we”添加到字符串常量池中,如果是这样,为什么即使 d 未指向字符串常量池,d==e
也会导致 true
最佳答案
正在延迟加载字符串池。如果您在字符串文字之前自己调用 intern(),那么这就是将进入字符串池的字符串版本。如果您自己不调用 intern(),那么字符串文字将为我们填充字符串池。
令人惊讶的是,我们可以在常量池之前影响字符串池;如以下代码片段所示。
要理解为什么这两个代码片段有不同的行为,重要的是要弄清楚
the constant pool is not the same as the string pool .也就是说,常量池是存储在磁盘上的类文件的一部分,字符串池是填充了字符串的运行时缓存。
引用字符串文字并不直接引用常量池,而是根据 Java 语言规范 jls-3.10.5 ;当且仅当字符串池中还没有值时,字 rune 字才会从常量池填充字符串池。
也就是说,一个String对象从源文件到运行时的生命周期是这样的:
- 在编译时由编译器放入常量池,并存储在生成的类文件中(每个类文件一个常量池)
- 常量池由 JVM 在类加载时加载
- 当调用 intern 时,从常量池创建的字符串在运行时添加到字符串池(如果等效字符串不存在,如果已经存在字符串,则将使用字符串池中的字符串) JVM Spec 5.1 - The Run-Time Constant Pool .
- 实习生可以通过手动调用 intern() 显式发生,也可以通过引用字符串文字(例如“abc”jls-3.10.5)隐式发生。 .
以下两个代码片段之间的行为差异是由于在通过字符串文字隐式调用 intern 之前显式调用 intern() 造成的。
为清楚起见,下面是对该答案的评论中讨论的两种行为的完整介绍:
String c = "qwe"; // string literal qwe goes into runtime cache
String d = c.substring(1); // runtime string "we" is created
d.intern(); // intern "we"; it has not been seen
// yet so this version goes into the cache
String e = "we"; // now we see the string literal, but
// a value is already in the cache and so
// the same instance as d is returned
// (see ref below)
System.out.println( e == d ); // returns true
下面是我们在使用字符串文字后进行实习时发生的情况:
String c = "qwe"; // string literal qwe goes into runtime cache
String d = c.substring(1); // runtime string "we" is created
String e = "we"; // now we see the string literal, this time
// a value is NOT already in the cache and so
// the string literal creates an object and
// places it into the cache
d.intern(); // has no effect - a value already exists
// in the cache, and so it will return e
System.out.println( e == d ); // returns false
System.out.println( e == d.intern() ); // returns true
System.out.println( e == d ); // still returns false
以下是 JLS 的关键部分,说明为字符串文字隐式调用了 intern。
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.
并且 JVM 规范详细介绍了从类文件加载的常量池的运行时表示以及它与 intern 的交互。
If the method String.intern has previously been called on an instance of class String containing a sequence of Unicode code points identical to that given by the CONSTANT_String_info structure, then the result of string literal derivation is a reference to that same instance of class String. .
关于java - 字符串常量池和实习生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33416740/