java - 字符串常量池和实习生

标签 java string string-literals

这几天我一直在尝试理解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(),那么字符串文字将为我们填充字符串池。

令人惊讶的是,我们可以在常量池之前影响字符串池;如以下代码片段所示。


要理解为什么这两个代码片段有不同的行为,重要的是要弄清楚

  1. the constant pool is not the same as the string pool .也就是说,常量池是存储在磁盘上的类文件的一部分,字符串池是填充了字符串的运行时缓存。

  2. 引用字符串文字并不直接引用常量池,而是根据 Java 语言规范 jls-3.10.5 ;当且仅当字符串池中还没有值时,字 rune 字才会从常量池填充字符串池。

也就是说,一个String对象从源文件到运行时的生命周期是这样的:

  1. 在编译时由编译器放入常量池,并存储在生成的类文件中(每个类文件一个常量池)
  2. 常量池由 JVM 在类加载时加载
  3. 当调用 intern 时,从常量池创建的字符串在运行时添加到字符串池(如果等效字符串不存在,如果已经存在字符串,则将使用字符串池中的字符串) JVM Spec 5.1 - The Run-Time Constant Pool .
  4. 实习生可以通过手动调用 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/

相关文章:

java - 如何在JKS中管理两个 key

java - 交换 2 个不同 AtomicReferences 中的 2 个值

java - 从 HashMap 中获取前 k 个值

c - C中单引号和双引号的区别

java - 使用 Moxy 解码 xml 文件并根据多个 XML 模式进行验证

java - SimpleDateFormat 未在单元测试中返回预期值

javascript - 从变量中删除 char 时出错

Objective-c 如何将 NSURL 转换成 NSString?

c - GCC __func__ 被评估为空字符串

c++ - 字符串数据类型如何存储为字节