JVM中的常量池解析
阿新 • • 發佈:2019-02-11
在jvm規範中,每個型別都有自己的常量池。常量池是某型別所用常量的一個有序集合,包括直接常量(基本型別,String)和對其他型別、欄位、方法的符號引用。之所以是符號引用而不是像c語言那樣,編譯時直接指定其他型別,是因為java是動態繫結的,只有在執行時根據某些規則才能確定具體依賴的型別例項,這正是java實現多型的基礎。
2=》8種基本型別的包裝類和物件池
java中基本型別的包裝類的大部分都實現了常量池技術,這些類是Byte,Short,Integer,Long,Character,Boolean,另外兩種浮點數型別的包裝類則沒有實現。另外Byte,Short,Integer,Long,Character這5種整型的包裝類也只是在對應值小於等於127時才可使用物件池,也即物件不負責建立和管理大於127的這些類的物件。以下是一些對應的測試程式碼:
3=》String也實現了常量池技術
4=》字串比較更豐富的一個例子
輸出結果的分別解釋如下:
在同包同類下,引用自同一String物件.
在同包不同類下,引用自同一String物件.
在不同包不同類下,依然引用自同一String物件
在編譯成.class時能夠識別為同一字串的,自動優化成常量,所以也引用自同一String物件
在執行時建立的字串具有獨立的記憶體地址,所以不引用自同一String物件
String的intern()方法會查詢在常量池中是否存在一份equal相等的字串,如果有則返回一個引用,沒有則新增自己的字串進進入常量池,
注意,只是字串部分,
所以這時會存在2份拷貝,常量池的部分被String類私有持有並管理,自己的那份按物件生命週期繼續使用.
為了對常量池有更具體的認識,下面引用幾個例子:
1=》常量池中物件和堆中的物件
public class Test{ Integer i1=new Integer(1); Integer i2=new Integer(1); //i1,i2分別位於堆中不同的記憶體空間 System.out.println(i1==i2);//輸出false Integer i3=1; Integer i4=1; //i3,i4指向常量池中同一個記憶體空間 System.out.println(i3==i4);//輸出true //很顯然,i1,i3位於不同的記憶體空間 System.out.println(i1==i3);//輸出false }
2=》8種基本型別的包裝類和物件池
java中基本型別的包裝類的大部分都實現了常量池技術,這些類是Byte,Short,Integer,Long,Character,Boolean,另外兩種浮點數型別的包裝類則沒有實現。另外Byte,Short,Integer,Long,Character這5種整型的包裝類也只是在對應值小於等於127時才可使用物件池,也即物件不負責建立和管理大於127的這些類的物件。以下是一些對應的測試程式碼:
public class Test{ public static void main(String[] args){ //5種整形的包裝類Byte,Short,Integer,Long,Character的物件, //在值小於127時可以使用常量池 Integer i1=127; Integer i2=127; System.out.println(i1==i2)//輸出true //值大於127時,不會從常量池中取物件 Integer i3=128; Integer i4=128; System.out.println(i3==i4)//輸出false //Boolean類也實現了常量池技術 Boolean bool1=true; Boolean bool2=true; System.out.println(bool1==bool2);//輸出true //浮點型別的包裝類沒有實現常量池技術 Double d1=1.0; Double d2=1.0; System.out.println(d1==d2)//輸出false } }
3=》String也實現了常量池技術
String類也是java中用得多的類,同樣為了建立String物件的方便,也實現了常量池的技術,測試程式碼如下:
public class Test{ public static void main(String[] args){ //s1,s2分別位於堆中不同空間 String s1=new String("hello"); String s2=new String("hello"); System.out.println(s1==s2)//輸出false //s3,s4位於池中同一空間 String s3="hello"; String s4="hello"; System.out.println(s3==s4);//輸出true } }
4=》字串比較更豐富的一個例子
package testPackage;
public class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((hello == "Hello") + " ");
System.out.print((Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
System.out.print((hello == ("Hel"+lo)) + " ");
System.out.println(hello == ("Hel"+lo).intern());
}
}
class Other { static String hello = "Hello"; }
package other;
public class Other { static String hello = "Hello"; }
SystemOut:true true true true false true
輸出結果的分別解釋如下:
在同包同類下,引用自同一String物件.
在同包不同類下,引用自同一String物件.
在不同包不同類下,依然引用自同一String物件
在編譯成.class時能夠識別為同一字串的,自動優化成常量,所以也引用自同一String物件
在執行時建立的字串具有獨立的記憶體地址,所以不引用自同一String物件
String的intern()方法會查詢在常量池中是否存在一份equal相等的字串,如果有則返回一個引用,沒有則新增自己的字串進進入常量池,
注意,只是字串部分,
所以這時會存在2份拷貝,常量池的部分被String類私有持有並管理,自己的那份按物件生命週期繼續使用.
轉自:http://www.cnblogs.com/wenfeng762/archive/2011/08/14/2137820.html