String的intern()方法 與執行時常量池(方法區)
阿新 • • 發佈:2018-12-09
String的intern()方法 與執行時常量池(方法區)
在你看這篇文章時我假設你已經瞭解jvm記憶體
1.String.intern()是一個Native方法,作用是:如果字串常量池存在字串相等(equals() )的字串物件,就返回此常量池中的String物件。否則將String物件新增到常量池中,並返回此String物件的引用。
2.Jdk1.6及其之前的版本,字串常量池分佈在永久帶(方法區)中,Intern()把首次遇到的字串複製到常量池中,返回的也是常量池中例項的引用。
3.jdk1.7以後字串常量池移到了堆中,Intern()不再複製例項,只是在常量池中記錄例項的引用,因此返回的引用和下面StringBuilder建立的例項是同一個。
public class Main {
public static void main(String[] args) {
String str1 = new StringBuilder("hu").append("xin").toString(); //new的物件放在堆裡
System.out.println(str1 == str1.intern());
}
}
此方法jdk1.6及其以前返回 false
jdk1.7及其以後返回 true
上面程式碼如果直接new String("hu")
或者去掉上面的.append("xin")
註解:JDK1.7為什麼要把字串常量池移動到堆裡面
在Java 7之前,JVM 將Java字串池放在永久代PermGen(方法區)中,該空間具有固定的大小 - 它不能在執行時擴充套件,也不在垃圾回收的範圍內。
在PermGen(方法區)中實現字串的風險是,如果我們定義太多字串,JVM可能報OutOfMemory錯誤。
從Java 7開始,Java字串池儲存在堆空間中,這是 JVM的垃圾收集範圍內。這種方法的優點是降低了OutOfMemory錯誤的風險,因為未引用的字串將從池中刪除,從而釋放記憶體。
字串總結
public class Main {
public static void main(String[] args) {
String str11 = new StringBuilder("hu").append("xin").toString(); //物件放在堆裡--採用new 建立的字串物件不進常量池
String str22 = new StringBuilder("hu").append("xin").toString(); //物件放在堆裡--採用new 建立的字串物件不進常量池
System.out.println(str11 == str22);
System.out.println(str11 == str11.intern()); //第一次呼叫Intern發現字串不存在常量池,(1.7 將str11的引用放入常量池)
System.out.println(str11 == str22.intern()); //第二次呼叫Intern發現字串存在常量池裡,返回常量池裡的引用
final String str1 = "a";
String str2 = "b";
String str3 = "ab";
String str4 = "a" + str2; //字串相加含有變數則不會進入常量池中
String str5 = new String("ab");
String str6 = "a"+"b"; //字串相加的時候,都是靜態字串的結果會新增到常量池
String str7 = str1 +"b" ; //對final變數的訪問在編譯期間都會直接被替代為真實的值 相當於靜態字串
System.out.println(str5 == str3);
System.out.println(str5.intern() == str3);
System.out.println(str5.intern() == str4);
System.out.println(str5.intern() == str6);
System.out.println(str5.intern() == str7);
}
}
結果
false
true
true
false
true
false
true
true
1.採用new 建立的字串物件不放入常量池
2.字串相加的時候,都是靜態字串的結果會新增到常量池,如果其中含有變數(如str1)則不會放入常量池中
3.對final變數的訪問在編譯期間都會直接被替代為真實的值 相當於靜態字串