jdk1.8下字符串常量的判斷,String.intern()分析


字符串常量池在jdk升級過程中發生了一些變化

      在JDK1.6中,它在方法區中,屬於“永久代”.

                     在JDK1.7中,它被移除方法區,放在java堆中。

                     在JDK1.8中,取消了“永久代”,將常量池放在元空間,與堆獨立

jdk1.6中,intern()方法會把首次遇到的字符串示例復制到永久代中,返回的也是永久代中這個字符串實例的引用

jdk1.6以后,對於實例,intern()方法不會再復制實例,只是在常量池中記錄首次出現的實例引用,對於字符串仍然是加入字符串常量

比如下面這段代碼,這段代碼在常量池加入的直接是“ab”的引用

String s = new String("a")+new String("b") s.intern()

 

創建字符串分析

以下轉自 https://blog.csdn.net/u013366617/article/details/83618361

1.直接使用雙引號創建字符串

 判斷這個常量是否存在於常量池,
  如果存在,
   判斷這個常量是存在的引用還是常量,
    如果是引用,返回引用地址指向的堆空間對象,
    如果是常量,則直接返回常量池常量,
  如果不存在,
    在常量池中創建該常量,並返回此常量

String a1 = "AA";//在常量池上創建常量AA
String a2 = "AA";//直接返回已經存在的常量AA
System.out.println(a1 == a2); //true
 String a3 = new String("AA"); //在堆上創建對象AA
a3.intern(); //在常量池上創建對象AA的引用
String a4 = "AA"; //常量池上存在引用AA,直接返回該引用指向的堆空間對象,即a3
System.out.println(a3 == a4); //false 這里一開始寫錯了
注意!!!對上面的做個小小的解釋
String a3 = new String("AA"); //在堆上創建對象AA a3.intern(); String a4 = "AA"; System.out.println(a3 == a4); //false 對比 String a3 = new String("AA").intern(); //在堆上創建對象AA String a4 = "AA"; System.out.println(a3 == a4); //true 是不是感覺很奇怪 原因是a3.intern()確實返回的是常量池里的引用,但是不是a3本身,a3本身還是實例對象的引用 如果這樣寫 String a3 = new String("AA"); //在堆上創建對象AA String a = a3.intern(); String a4 = "AA"; System.out.println(a == a4); //true

2.new String創建字符串

 首先在堆上創建對象(無論堆上是否存在相同字面量的對象),
 然后判斷常量池上是否存在字符串的字面量,
  如果不存在
   在常量池上創建常量
  如果存在
   不做任何操作

String a1 = new String("AA"); String a2 = new String("AA"); System.out.println(a1 == a2); //false //如果常量池上不存在常量AA,也不存在引用AA,則創建常量AA
String a1 = new String("AA"); System.out.println(a1 == a1.intern()); //false


3.雙引號相加

 判斷這兩個常量、相加后的常量在常量池上是否存在
  如果不存在
   則在常量池上創建相應的常量
  如果存在
   判斷這個常量是存在的引用還是常量,
    如果是引用,返回引用地址指向的堆空間對象,
    如果是常量,則直接返回常量池常量,

String a1 = "AA" + "BB";//在常量池上創建常量AA、BB和AABB,並返回AABB //常量池上存在常量AABB
String a2 = "AABB"; String a3 = "AA" + "BB"; System.out.println(a2 == a3); //true //常量池上存在引用AABB
String a4 = new String("AA") + new String("BB"); //在堆上創建對象AA、BB和AABB,在常量池上創建常量AA和BB
a4.intern(); String a5 = "AA" + "BB"; System.out.println(a4 == a5); //true

 

4.兩個new String相加

 首先會創建這兩個對象以及相加后的對象
 然后判斷常量池中是否存在這兩個對象的字面量常量
  如果存在
   不做任何操作
  如果不存在
   則在常量池上創建對應常量

//常量AA不存在,所以第一步在常量池中創建了常量AA
String a2 = new String("AA") + new String("BB"); String a3 = new String("A")+new String("A"); //創建對象AA
System.out.println(a3 == a3.intern()); //false //只在堆上創建AABB對象,沒有在常量池中創建常量AABB
String a2 = new String("AA") + new String("BB"); System.out.println(a2 == a2.intern()); //true


5.雙引號字符串與new String字符串

 首先創建兩個對象,一個是new String的對象,一個是相加后的對象
 然后判斷雙引號常量與new String的字面量在常量池是否存在
  如果存在
   不做操作
  如果不存在
   則在常量池上創建對象的常量

String a1 = "AABB"; String a2 = "AA" + new String("BB"); System.out.println(a1 == a2.intern());//true
System.out.println(a2 == a2.intern()); //false

二.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 a3 = new String("AA");


4.在堆上創建對象,在常量池上創建引用

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

練習

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