Java字符串常亮池

http://blog.csdn.net/u010297957/article/details/50995869

概念:

一、常量池表(constant_pool table) 

        Class文件中存儲全部常量(包括字符串)的tablejava

        這是Class文件中的內容,還不是運行時的內容,不要理解它是個池子,其實就是Class文件中的字節碼指令.程序員

二、運行時常量池(Runtime Constant Pool)

        JVM內存中方法區的一部分,這是運行時的內容面試

        這部份內容(絕大部分)是隨着JVM運行時候,從常量池轉化而來,每一個Class對應一個運行時常量池設計模式

        2中說絕大部分是由於:除了 Class中常量池內容,還可能包括動態生成並加入這裏的內容spa

3. 字符串常量池(String Pool)

這部分也在方法區中,但與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. 首先,1"asd"會在通過javac(或者其餘編譯器)編譯事後變爲Class文件中constant_pool table的內容

  2. 當咱們的程序運行時,也就是說JVM運行時,每一個Classconstant_pool table中的內容會被加載到JVM內存中的方法區中各自Class的Runtime Constant Pool

  3. 一個沒有被String Pool包含的Runtime Constant Pool中的字符串(這裏是"asd")會被加入到String Pool中(HosSpot使用hashtable引用方式),步驟以下:

    1. 在Java Heap中根據"asd"字面量create一個字符串對象
    2. 將字面量"asd"與字符串對象的引用在hashtable中關聯起來,鍵 - 值 形式是:"asd" = 對象的引用地址

另外來講,當一個新的字符串出如今Runtime Constant Pool中時怎麼判斷需不須要在Java Heap中建立新對象呢?

策略是這樣:會先去根據equals來比較Runtime Constant Pool中的這個字符串是否和String Pool中某一個是相等的(也就是找是否已經存在),若是有那麼就不建立,直接使用其引用;反之,如上3

如此,就實現了享元模式,提升的內存利用效率

2. 例子

上面的描述其實對於能看到這篇文章的程序員們來講很好懂,下面咱們來找一些面試題練練手吧

1. String s = new String(「abc」) 建立了幾個對象?

答:

2個

解析:

  1. 首先,出現了字面量"abc",那麼去String Pool中查找是否有相同字符串存在,由於程序就這一行代碼因此確定沒有,那麼就在Java Heap中用字面量"abc"首先建立1個String對象

  2. 接着,new String("abc"),關鍵字new又在Java Heap中建立了1個對象,而後調用接收String參數的構造器進行了初始化。最終s的引用是這個String對象

    如上:2個

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. 首先,根據題1所述,這裏同理,s1和s2確定不是一個引用;

  2. 其次String s3 = "a" + "bc";這行代碼最終是"abc",根據s1,它已經在String pool中了,因此s3和s1是引用的同一個對象;

  3. 最後,s1.intern()方法:將某個String對象在運行期動態的加入String pool(若是pool中已經有一個了就不加)並返回String pool中保證惟一的一個字符串對象的引用。  因此,仍是會返回和s1同一個對象的引用,因此true;

相關文章
相關標籤/搜索