Class文件中存儲全部常量(包括字符串)的tablejava
這是Class文件中的內容,還不是運行時的內容,不要理解它是個池子,其實就是Class文件中的字節碼指令.程序員
JVM內存中方法區的一部分,這是運行時的內容面試
這部份內容(絕大部分)是隨着JVM運行時候,從常量池轉化而來,每一個Class對應一個運行時常量池設計模式
2中說絕大部分是由於:除了 Class中常量池內容,還可能包括動態生成並加入這裏的內容spa
這部分也在方法區中,但與Runtime Constant Pool不是一個概念,String Pool是JVM實例全局共享的,全局只有一個.net
JVM規範要求進入這裏的String實例叫「被駐留的interned string」,各個JVM能夠有不一樣的實現,HotSpot是設置了一個哈希表StringTable來引用堆中的字符串實例,被引用就是被駐留設計
(JDK1.6字符串常量池在方法區中存儲,JDK1.7中放在了堆。(不知道正確性在一個ppt中看到的,不過和上面這句話形容的同樣。))code
這裏的使用了一種設計模式:享元模式。也就是說:一個系統中若是有多處用到了相同的一個元素,那麼咱們應該只存儲一份此元素,而讓全部地方都引用這一個元素。對象
我覺的好像前面1和2隨便說了點概念,就好像快說完了……blog
那麼,來個Example吧!在*.java文件中有以下代碼:
int a = 1; String b = "asd";
首先,1
和"asd"
會在通過javac(或者其餘編譯器)編譯事後變爲Class文件中constant_pool table
的內容
當咱們的程序運行時,也就是說JVM運行時,每一個Classconstant_pool table
中的內容會被加載到JVM內存中的方法區中各自Class的Runtime Constant Pool
一個沒有被String Pool
包含的Runtime Constant Pool
中的字符串(這裏是"asd"
)會被加入到String Pool
中(HosSpot使用hashtable引用方式),步驟以下:
"asd"
字面量create
一個字符串對象"asd"
與字符串對象的引用在hashtable中關聯起來,鍵 - 值 形式是:"asd"
= 對象的引用地址
另外來講,當一個新的字符串出如今Runtime Constant Pool
中時怎麼判斷需不須要在Java Heap中建立新對象呢?
策略是這樣:會先去根據equals來比較Runtime Constant Pool
中的這個字符串是否和String Pool
中某一個是相等的(也就是找是否已經存在),若是有那麼就不建立,直接使用其引用;反之,如上3
如此,就實現了享元模式,提升的內存利用效率
上面的描述其實對於能看到這篇文章的程序員們來講很好懂,下面咱們來找一些面試題練練手吧
2個
首先,出現了字面量"abc"
,那麼去String Pool
中查找是否有相同字符串存在,由於程序就這一行代碼因此確定沒有,那麼就在Java Heap中用字面量"abc"
首先建立1個String對象
接着,new String("abc")
,關鍵字new又在Java Heap中建立了1個對象,而後調用接收String參數的構造器進行了初始化。最終s
的引用是這個String對象
如上:2個
public static void main(String[] args) { String s1 = "abc"; String s2 = new String("abc"); String s3 = "a" + "bc"; System.out.println(s1 == s2); System.out.println(s1 == s3); System.out.println(s1 == s1.intern()); }
System.out.println(s1 == s2);//flase System.out.println(s1 == s3);//true System.out.println(s1 == s1.intern());//true
首先,根據題1所述,這裏同理,s1和s2確定不是一個引用;
其次String s3 = "a" + "bc";
這行代碼最終是"abc"
,根據s1,它已經在String pool
中了,因此s3和s1是引用的同一個對象;
最後,s1.intern()方法:將某個String對象在運行期動態的加入String pool
(若是pool中已經有一個了就不加)並返回String pool
中保證惟一的一個字符串對象的引用。 因此,仍是會返回和s1同一個對象的引用,因此true;