String中intern方法的作用


詳見:https://blog.csdn.net/guoxiaolongonly/article/details/80425548

1.常量池存放於方法區中

2.jdk1.6 方法區放在永久代(java堆的一部分),jdk1.7 特別將字符串常量池移動到了的堆內存中(使用參數-XX:PermSize 和-XX:MaxPermSize指定大小),jdk1.8放在單獨的元空間里面(-XX:MaxMetaspaceSzie設定大小),和堆相獨立。所以導致string的intern方法因為以上變化在不同版本會有不同表現。

3.jdk1.6將Hotspot虛擬機使用永久代來實現方法區,因為方法區的內存回收跟堆內存回收其實沒什么區別,這樣實現可以用垃圾收集器來管理這部分內存,但這樣容易導致內存溢出(達到-XX:MaxPermSize)。

JDK1.6,JDK1.7常量池的存放如下都存放於堆內存中

JDK1.8常量池的存放如下

具體可參考:https://blog.csdn.net/zhyhang/article/details/17246223/

知道了常量池在內存中的存放后,我們需要先了解一下 String str=“abc”;和 String str =new String(“abc”);的區別

1.String str=“abc”;

JDK1.6
(1) 當常量池中不存在"abc"這個字符串的引用,在堆內存中new一個String對象,復制這個對象加入常量池,返回常量池中的對象。

(2) 當常量池中存在"abc"這個字符串對象,str指向這個對象的引用;

 

JDK1.7以上
(1) 當常量池中不存在"abc"這個字符串的引用,在堆內存中new一個新的String對象,將這個對象的引用加入常量池。(跟1.6的區別是常量池不再存放對象,只存放引用。)
(2) 當常量池中存在"abc"這個字符串的引用,str指向這個引用;

2.String str =new String(“abc”)

單純的在堆內存中new一個String對象,通過StringBuilder 跟StringBuffer 構建的對象也是一樣

3.intern方法 (返回常量池中該字符串的引用)

(1) 當常量池中不存在"abc"這個字符串的引用,將這個對象的引用加入常量池,返回這個對象的引用。
(2) 當常量池中存在"abc"這個字符串的引用,返回這個對象的引用;

 詳見:http://www.cnblogs.com/think-in-java/p/10418915.html

測試環境JDK1.8

常量池可以存放引用,也可以存放常量

String.intern()分析

 判斷這個常量是否存在於常量池。
  如果存在
   判斷存在內容是引用還是常量,
    如果是引用,
     返回引用地址指向堆空間對象,
    如果是常量,
     直接返回常量池常量
  如果不存在,
   將當前對象引用復制到常量池,並且返回的是當前對象的引用

   String a1 = "AA";
    System.out.println(a1 == a1.intern()); //true
    String a2 = new String("B") + new String("B");
    a2.intern();
    String a3 = new String("B") + new String("B");
    System.out.println(a2 == a3.intern());//true
    System.out.println(a3 == a3.intern());//false
    String a4 = new String("C") + new String("C");
    System.out.println(a4 == a4.intern()); //true

三.總結 

1.只在常量池上創建常量

   String a1 = "AA";

2.只在堆上創建對象

  String a2 = new String("A") + new String("A");

3.在堆上創建對象,在常量池上創建常量

  String a4 = new String("A") + new String("A");//只在堆上創建對象AA
    a4.intern();//將該對象AA的引用保存到常量池上

5.在堆上創建對象,在常量池上創建引用, 在常量池上創建常量(不可能)

 String a5 = new String("A") + new String("A");//只在堆上創建對象
    a5.intern();//在常量池上創建引用
    String a6 = "AA";//此時不會再在常量池上創建常量AA,而是將a5的引用返回給a6
    System.out.println(a5 == a6); //true

6.

四.練習

String aa = "AA";//設置常量AA到常量池
         String bb = "BB";//設置常量BB到常量池
         String ccdd = "CC"+"DD";//設置常量CCDD到常量池
         String neeff = new String("EE")+new String("FF");//設置EE和FF到常量池。並且添加EE、FF和EEFF對象到堆
         String aabb = aa+bb;//添加AABB對象到堆
         String gghh = "GG"+new String("HH");//設置GG和HH常量到常量池,設置HH和GGHH對象到堆
//         aa.intern();//啥事都不做,返回AA常量
//         ccdd.intern();//啥事都不做,返回CCDD常量
//         neeff.intern();//添加EEFF對象的引用到常量池,並返回EEFF對象
//         aabb.intern();//添加AABB對象的引用到常量池,並返回AABB對象
//         gghh.intern();//添加GGHH對象的引用到常量池,並返回GGHH對象
         System.out.println(aa.intern()==aa); //true
         System.out.println(neeff.intern()=="EEFF");//true
         System.out.println("EEFF"==neeff);//true
         String nccdd = new String("CCDD");
         System.out.println(ccdd==nccdd);//false
         System.out.println(ccdd==nccdd.intern());//true
         System.out.println(aabb.intern()==aabb);//true
         System.out.println(gghh==gghh.intern());//true

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM