1. 程式人生 > >JVM中的常量池解析

JVM中的常量池解析

在jvm規範中,每個型別都有自己的常量池。常量池是某型別所用常量的一個有序集合,包括直接常量(基本型別,String)和對其他型別、欄位、方法的符號引用。之所以是符號引用而不是像c語言那樣,編譯時直接指定其他型別,是因為java是動態繫結的,只有在執行時根據某些規則才能確定具體依賴的型別例項,這正是java實現多型的基礎。

為了對常量池有更具體的認識,下面引用幾個例子:

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