看了幾篇關于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) {
//在常量池中添加字元串hello
String 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); //true
String s3="helloWorld";
//常量池中已經存在"helloWorld"的引用,是以s3也直接指向堆中的字元串
System.out.println(s3==s1); //true
}
關于intern()方法為什麼能夠節省記憶體,參見 Java技術——你真的了解String類的intern()方法嗎