看了幾篇關於intern方法的文章,總結如下:
一、主要知識點:
1、使用引號聲明的字串常量都會直接在字串常量池中產生
2、intern方法在jdk1.6與jdk1.7中有點區別,主要原因是jdk1.7中將常量池移到了堆中
3、使用intern方法會很大程度的節省記憶體
二、Java中字串建立的兩種方式:
Java中字串對象建立有兩種形式,
一種為字面量形式,如String str=" hello",
另一種就是使用標準的構造對象的方法,如String str=new String("hello");
這兩種經常使用,在記憶體上面有一些區別。這一切都是JVM為了減少字串對象重複建立,其維護了一個特殊的記憶體,這段記憶體就是字串常量池
工作原理
當代碼中出現字面量形式建立字串對象時嗎,JVM就會首先對這個字面量進行檢查,,如果字串常量池中存在相同內容的字串對象的引用,則將這個引用返回,否則新的字串對象就被建立,然後將這個引用放入字串常量池中,並返回該引用。
String str1="hello"
JVM檢測這個字面量,這裡我們認為沒有內容為"hello"的對象存在。JVM通過字串常量池尋找不到內容為"hello"的字串對象存在,那麼會建立這個字串對象,然後將剛建立的對象的引用放入到字串常量池中,並且將引用返回給變數str1。
String str2="hello"
同樣JVM還是要檢測這個字面量,JVM通過尋找字串常量池,發現內容為”droid”字串對象存在,於是將已經存在的字串對象的引用返回給變數str2。注意這裡不會重新建立新的字串對象。
驗證是否為str1和str2是否指向同一對象,我們可以通過這段代碼 System.out.println(str1 == str2);
結果為true。
String str3 = new String("hello");
當我們使用了new來構造字串對象的時候,不管字串常量池中有沒有相同內容的對象的引用,新的字串對象都會建立。因此我們使用下面代碼測試一下,
String str3 = new String("hello");
System.out.println(str1 == str3);
結果如我們所想,為false,表明這兩個變數指向的為不同的對象。
三、JDK1.6與JDK1.7中intern方法的區別:
1、JDK1.6中
在JDK1.6中,常量池是放在Perm區(屬於方法區)中的,這是和堆區完全分開的。
在JDK1.6中,intern()方法的作用:
檢查字串池裡是否存在"hello"這麼一個字串,如果存在,就返回池裡的字串;如果不存在,該方法會把"hello"添加到字串池中,然後再返回它的引用。
(1)
public static void main(String[] args) {//在常量池中添加字串helloString s1="hello";//由於常量池中已經存在"hello",所以返回該字串String s2=s1.intern();System.out.println(s2); //hello//s1和s2都指向常量池中"hello"System.out.println(s2==s1); //true}
(2)
public static void main(String[] args) {//在堆中建立字串並且在常量池中添加字串hello 因為使用引號聲明的字串常量都會直接在字串常量池中產生String s1=new String("hello");//由於常量池中已經存在"hello",所以返回該字串String s2=s1.intern();System.out.println(s2); //hello//由於s1指向的字串在堆中,而s2指向的字串在常量池中,所以地址不同(==判斷的是地址)System.out.println(s2==s1); //false}
(3)
public static void main(String[] args) {//在堆中建立字串"hello world" 在常量池中分別建立"hello"與"world"String s1=new String("hello")+new String("World");//由於常量池中不存在"hello world",所以添加該字串,並返回引用String s2=s1.intern();System.out.println(s2); //helloWorld//由於s1指向的字串在堆中,而s2指向的字串在常量池中,所以地址不同(==判斷的是地址)System.out.println(s2==s1); //false}
注意:在jdk1.7中會輸出true,下面將介紹。
2、在JDK1.7中
在JDK1.7中,將常量池放到了堆中。
正常情況下,使用new建立的字串對象的引用不會放入字串常量池,但是在使用JDK1.7的情況下,如果想將這個對象的引用加入到字串常量池,可以使用intern方法。調用intern後,首先檢查字串常量池中是否有該對象的引用,如果存在,則將這個引用返回給變數,否則將引用加入並返回給變數。
public static void main(String[] args) {//在堆中建立字串"hello world" 在常量池中分別建立"hello"與"world"String s1=new String("hello")+new String("World");/* * 由於常量池中不存在"hello world",但是在堆中有該字串, * 所以將引用s1返回,即s2也指向堆中的字串 */String s2=s1.intern();System.out.println(s2); //helloWorld//所以地址相同System.out.println(s2==s1); //trueString s3="helloWorld";//常量池中已經存在"helloWorld"的引用,所以s3也直接指向堆中的字串System.out.println(s3==s1); //true}
關於intern()方法為什麼能夠節省記憶體,參見 Java技術——你真的瞭解String類的intern()方法嗎