簡體   English   中英

字符串常量池和實習生

[英]String Constant Pool and intern

我最近幾天試圖理解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”添加到String consant池中,如果是這樣,為什么d==e結果為true,即使d未指向String Constant池也是如此

字符串池正在延遲加載。 如果你在字符串文字之前自己調用intern(),那么這是將進入字符串池的字符串的版本。 如果你不自己調用intern(),那么字符串文字將為我們填充字符串池。

令人驚訝的是,我們可以在常量池之前影響字符串池; 正如下面的代碼片段所示。


要理解為什么兩個代碼片段具有不同的行為,重要的是要明確這一點

  1. 常量池與字符串池不同 也就是說,常量池是存儲在磁盤上的類文件的一部分,字符串池是用字符串填充的運行時緩存。

  2. 並且引用字符串文字並不直接引用常量池,而是根據Java語言規范jls-3.10.5 ; 當且僅當字符串池中沒有值時,字符文字才會從常量池填充字符串池。

也就是說,從源文件到運行時的String對象的生命周期如下:

  1. 編譯器在編譯時放入常量池並存儲在生成的類文件中(每個類文件有一個常量池)
  2. JVM在類加載時加載常量池
  3. 從常量池創建的字符串在運行時被添加到字符串池中,因為調用了intern(如果還沒有等效的字符串,如果已經存在字符串,那么將使用字符串池中的字符串) JVM Spec 5.1 - 運行時常量池
  4. 實習可以通過手動調用intern()或隱式引用字符串文字(如“abc” jls-3.10.5 )來顯式發生。

以下兩個代碼片段之間的行為差​​異是由於在通過字符串文字發生對內部的隱式調用之前顯式調用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的關鍵部分,聲明實際上是為字符串文字調用實習生。

此外,字符串文字始終引用類String的相同實例。 這是因為字符串文字 - 或者更常見的是作為常量表達式(第15.28節)的值的字符串 - 被“實例化”以便使用String.intern方法共享唯一實例。

JVM規范涵蓋了從類文件加載的常量池的運行時表示的詳細信息,並且它與實習生交互。

如果先前在類String的實例上調用了String.intern方法,該類包含與CONSTANT_String_info結構給出的Unicode代碼點序列相同的Unicode代碼點序列,則字符串文字派生的結果是對類String的同一實例的引用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM