在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相等的字元串,如果有則傳回一個引用,沒有則添加自己的字元串進進入常量池,
注意,隻是字元串部分,