java常量池技术
轉載自? ?java常量池技術
摘要:?簡介 ? ? 常量池在java用于保存在編譯期已確定的,已編譯的class文件中的一份數據。它包括了關于類,方法,接口等中的常量,也包括字符串常量,如String s = "java"這種申明方式;當然也可擴充,執行器產生的常量也會放入常量池,故認為常量池是JVM的一塊特殊的內存空間。
簡介
? ? 常量池在java用于保存在編譯期已確定的,已編譯的class文件中的一份數據。它包括了關于類,方法,接口等中的常量,也包括字符串常量,如String s = "java"這種申明方式;當然也可擴充,執行器產生的常量也會放入常量池,故認為常量池是JVM的一塊特殊的內存空間。
Java是一種動態鏈接的語言,常量池的作用非常重要,常量池中除了包含代碼中所定義的各種基本類型(如int、long等等)和對象型(如String及數組)的常量值外,還包含一些以文本形式出現的符號引用,比如:類和接口的全限定名;字段的名稱和描述符;方法的名稱和描述符。在C語言中,如果一個程序要調用其它庫中的函數,在鏈接時,該函數在庫中的位置(即相對于庫文件開頭的偏移量)會被寫在程序中,在運行時,直接去這個地址調用函數;而在Java語言中不是這樣,一切都是動態的。編譯時,如果發現對其它類方法的調用或者對其它類字段的引用的語句,記錄進class文件中的只能是一個文本形式的符號引用,在連接過程中,虛擬機根據這個文本信息去查找對應的方法或字段。所以,與Java語言中的所謂“常量”不同,class文件中的“常量”內容很豐富,這些常量集中在class中的一個區域存放,一個緊接著一個,這里就稱為“常量池”。java中基本類型的包裝類的大部分都實現了常量池技術,這些類是Byte,Short,Integer,Long,Character,Boolean,另外兩種浮點數類型的包裝類則沒有實現。另外Byte,Short,Integer,Long,Character這5種整型的包裝類也只是在對應值小于等于127時才可使用對象池,也即對象不負責創建和管理大于127的這些類的對象。
java中的常量池技術,是為了方便快捷地創建某些對象而出現的,當需要一個對象時,就可以從池中取一個出來(如果池中沒有則創建一個),則在需要重復重復創建相等變量時節省了很多時間。常量池其實也就是一個內存空間,不同于使用new關鍵字創建的對象所在的堆空間。
常量池中對象和堆中的對象:
public class Test{public static void main(String[] args){Integer i1=new Integer(1);Integer i2=new Integer(1);//i1,i2分別位于堆中不同的內存空間System.out.println(i1==i2);//輸出falseInteger i3=1;Integer i4=1;//i3,i4指向常量池中同一個內存空間System.out.println(i3==i4);//輸出true//很顯然,i1,i3位于不同的內存空間System.out.println(i1==i3);//輸出false} }
8種基本類型的包裝類和對象池:
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} }
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} }
用new String()創建的字符串不是常量,不能在編譯期就確定,所以new String()創建的字符串不放入常量池中,他們有自己的地址空間。String 對象(內存)的不變性機制會使修改String字符串時,產生大量的對象,因為每次改變字符串,都會生成一個新的String。 java 為了更有效的使用內存,常量池在編譯期遇見String 字符串時,它會檢查該池內是否已經存在相同的String 字符串,如果找到,就把新變量的引用指向現有的字符串對象,不創建任何新的String 常量對象,沒找到再創建新的。所以對一個字符串對象的任何修改,都會產生一個新的字符串對象,原來的依然存在,等待垃圾回收。
最后
在JDK5.0之前是不允許直接將基本數據類型的數據直接賦值給其對應地包裝類的,如:Integer i = 5;?
但是在JDK5.0中支持這種寫法,因為編譯器會自動將上面的代碼轉換成如下代碼:Integer i=Integer.valueOf(5); ?
這就是Java的裝箱.JDK5.0也提供了自動拆箱.?Integer i =5; ?int j = i;??
總結
- 上一篇: 脲醛怎么读 脲醛读音和解释
- 下一篇: JVM调优总结(1):一些概念