2010-08-10 40 views
17

受到關於this question的評論的啓發,我很確定Java在運行時是被執行的而不是編譯時間 - 當然只是類可以在不同時間編譯的事實,但仍然會在運行時指向相同的引用。何時Java字符串被攔截?

我似乎無法找到任何證據來支持這件事。任何人都可以證明這一點?

回答

16

優化發生(或至少可能發生),在這兩個地方:

  • 如果兩個引用相同的字符串常量出現在同一個班級,我期望的類文件只包含一個常數池入口。這不是嚴格的要求爲了確保在JVM中只有一個String對象創建,但它是一個明顯的優化。這實際上並沒有實習 - 只是不斷的優化。
  • 當加載類時,該類的字符串池被添加到內部池中。這是「真正的」實習。

(我有一個模糊的記憶,對於Java 7圍繞「小jar文件」的工作位中的一個包括整個jar文件一個字符串池......但我可能是非常錯誤的。)

編輯:JVM規範的第5.1節,"The Runtime Constant Pool"進入這個細節:

爲了得到一個字符串,在Java 虛擬機檢查由 CONSTANT_String_info結構給出的字符序列 。

  • 如果該方法已的String.intern先前 被稱爲上含有序列由CONSTANT_String_info 結構給定的Unicode字符相同 ,那麼字符串的結果 字面的類字符串的實例 推導是對 的引用,表示String類的同一個實例。

  • 否則,類 字符串的新實例被創建含有由CONSTANT_String_info結構給出 Unicode字符 序列; 該類實例是 字符串文字派生的結果。最後,調用新字符串 實例的實例方法 。

+0

我記得我讀過的地方說過字符串池的作用域是封裝。我不記得它的來源 – 2010-08-10 16:29:21

+0

@丹尼斯:這聽起來不準確。據我所知,JLS的3.10.5節沒有提及。 – 2010-08-10 16:32:30

+0

(+1)我跟着[導致這個問題的評論]中的鏈接(http://stackoverflow.com/questions/3450604/why-is-there-no-string-empty-in-java/3450623# 3450623)以參考相同的文件回答,只是發現Jon Skeet已經在案件中。 :P – 2010-08-10 16:41:01

0

運行時間。

JLS和JVM規範指定將javac編譯爲包含常量聲明(在常量池中)和代碼中的常量用法(其中javac可以內聯爲基本/對象引用值)的類文件。對於編譯時的字符串常量,編譯器會生成代碼來構造String實例併爲它們調用String.intern(),以便JVM自動執行字符串常量。這是從一個JLS行爲要求:字符串型的

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28

編譯時常量表達式總是「實習」,以便共享獨特實例,使用該方法的String.intern。

但是這些規範既沒有概念也沒有定義任何特定的String intern池結構/引用/句柄,無論是編譯時還是運行時。 (當然,一般來說,JVM規範並不要求對象的任何特定內部結構:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.7

沒有提到內部池結構的原因是因爲它們完全由String類處理。 intern池是String類的私有靜態/類級結構(未由JLS & JVM規範& javadoc指定)。

在運行時調用String.intern()時,會將對象添加到內部池中。 Intern池由String類私人使用 - 當代碼創建新的String實例並調用String.intern()時,String類將確定是否重用現有的內部數據。優化可以由JIT編譯器在運行時執行。

這裏沒有編譯時間的貢獻,禁止將常量值的vanilla內聯。

+0

「隨着代碼嘗試創建新的'String'實例」。真?或者只是'字符串'文字? – Raedwald 2013-05-28 07:54:57

+0

已澄清 - String.intern()是String類的內部嘗試從池中重用元素的觸發器。當然,這對編譯時的字符串常量(文字和固定表達式)是隱含的。也可能由開發人員明確地調用。 – 2013-05-28 08:39:11