1.java常量池的介紹
java中的常量池,通常指的是運行時常量池,它是方法區的一部分,一個jvm實例只有一個運行常量池,各線程間共享該運行常量池。
java常量池簡介:java常量池中保存了一份在編譯期間就已確定的數據。它里面包括final常量的值(包括成員常量、局部常量和引用常量)、以及對象字面量的值。
在編譯期間,每當給常量賦值它就會去檢測常量池中是否存在該值,若存在直接返回該值的地址給常量,若不存在則先在常量池中創建該值,再返回該值的地址給常量。因此常量池中不可能出現相等的數據。
2.final常量
一切經final關鍵字修飾的變量均為常量,final常量必須在定義時就賦初值,否則編譯不通過。
3.對象字面量
對象字面量是指直接以一常量給對象賦值,而不是在堆空間new出一個對象實例。
常見的兩種對象字面量:基本類型的包裝類對象字面量、String對象字面量。
3.1基本類型的包裝類對象字面量
java中基本類型的包裝類大都實現了常量池技術,即Byte,Short,Integer,Long,Character,Boolean。這5種包裝類默認創建了數值[-128,127]的相應類型的緩存數據,但是超出此范圍仍然會去創建新的對象。 兩種浮點數類型的包裝類Float,Double並沒有實現常量池技術。
包裝類型Integer與常量池
Integer i1 = 40; Integer i2 = 40; Integer i3 = 0; Integer i4 = new Integer(40); Integer i5 = new Integer(40); Integer i6 = new Integer(0); System.out.println("i1=i2 " + (i1 == i2)); System.out.println("i1=i2+i3 " + (i1 == i2 + i3)); System.out.println("i1=i4 " + (i1 == i4)); System.out.println("i4=i5 " + (i4 == i5)); System.out.println("i4=i5+i6 " + (i4 == i5 + i6)); System.out.println("40=i5+i6 " + (40 == i5 + i6)); i1=i2 true i1=i2+i3 true i1=i4 false i4=i5 false i4=i5+i6 true 40=i5+i6 true
解釋:
- Integer i1=40;直接以字面量給對象賦值,它會先去檢查常量池中是否存在該值,若存在直接返回該值的地址,若不存在則現在常量池中創建該值,再返回該值的地址。
- Integer i1 = new Integer(40);這種情況會在堆空間創建新的對象。
- 語句i4 == i5 + i6,因為+這個操作符不適用於Integer對象,首先i5和i6進行自動拆箱操作,進行數值相加,即i4 == 40。然后Integer對象無法與數值進行直接比較,所以i4自動拆箱轉為int值40,最終這條語句轉為40 == 40進行數值比較。
3.2String對象字面量
String str1 = "abcd"; String str2 = new String("abcd"); System.out.println(str1==str2);//false String str1 = "str"; String str2 = "ing"; String str3 = "str" + "ing"; String str4 = str1 + str2; System.out.println("string" == "str" + "ing");// true System.out.println(str3 == str4);//false String str5 = "string"; System.out.println(str3 == str5);//true
解釋:
- 引用str1指向常量池中字符串"abcd"的地址,是在常量池中拿對象,new String("abcd")是直接在堆內存空間創建一個新的對象。只要使用new方法,便需要創建新的對象。
- 連接表達式 +,只有使用引號包含文本的方式創建的String對象之間使用“+”連接產生的新對象才會被加入常量池中。
- 對於字符串變量的“+”連接表達式,它所產生的新對象都不會被加入字符串池中,其屬於在運行時創建的字符串,具有獨立的內存地址,所以不引用自同一String對象。
(3)String.intern()方法強制將字符串放入常量池中
public static void main(String[] args) { String s1 = new String("計算機"); String s2 = s1.intern(); String s3 = "計算機"; System.out.println("s1 == s2? " + (s1 == s2)); System.out.println("s3 == s2? " + (s3 == s2)); } s1 == s2? false s3 == s2? true
解釋:String的intern()方法會查找在常量池中是否存在一份equal相等的字符串,如果有則返回該字符串的引用,如果沒有則添加自己的字符串進入常量池。
注意:final常量必須在定義時就賦初值,但對象字面量可以先定義后賦值。
4. 常量池的好處
常量池是為了避免頻繁的創建和銷毀對象而影響系統性能,實現了常量池中的內容由對象共享。例如字符串常量池,在編譯階段就把所有的字符串文字放到一個常量池中。
- 節省內存空間:常量池中所有相同的字符串常量被合並,只占用一個空間。
- 節省運行時間:比較字符串時,==比equals()快。對於兩個引用變量,只用==判斷引用是否相等,也就可以判斷實際值是否相等。
注:==號比較基本數據類型是值比較,但比較引用類型則是引用所指向的地址比較。
參考的博文:java常量池技術