文章目錄
- Class常量池
- 運行時常量池
- String常量池
- 基本類型常量池
- Integer 常量池
- Long 常量池
- 加餐部分
Class常量池
每個Class字節碼文件中包含類常量池用來存放字面量以及符號引用等信息。
運行時常量池
java文件被編譯成class文件之后,也就是會生成我上面所說的 class常量池,那么運行時常量池又是什么時候產生的呢?
jvm在執行某個類的時候,必須經過加載、連接、初始化,而連接又包括驗證、準備、解析三個階段。而當類加載到內存中后,jvm就會將 class常量池 中的內容存放到 運行時常量池 中。
在上面我也說了,class常量池 中存的是字面量和符號引用,也就是說他們存的并不是對象的實例,而是對象的符號引用值。而經過解析(resolve)之后,也就是把符號引用替換為直接引用。
運行時常量池區域是在方法區中。
String常量池
在JDK1.7后String常量池的所在區域被挪至堆內存中,原位置是在運行時常量池中,而在JDK1.7后JDK在堆內開辟了一塊空間用作了String常量池。
String name="zhangsan";
String nameTwo=new String("lisi");
上述兩行代碼中“zhangsan”字面量是存儲在String常量池中,而“lisi”則是在String常量池以及堆中各有一份,使用nameTwo時獲取lisi時也是從堆中獲取。
基本類型常量池
基本類型的常量池更偏向于緩存的概念,每個基本類型的包裝類都有對應的內部緩存類,若發現所需數據已完成緩存則直接從緩存對象的cache數組中獲取。整數、字符類型的最大緩存值為127而最小緩存值為-128,浮點型沒有緩存。
private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}}
Integer 常量池
當發現所需的值小于最小緩存值并且大于最大緩存值后,則直接創建新的對象
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
Long 常量池
當發現所需的值小于最小緩存值并且大于最大緩存值后,則直接創建新的對象
public static Long valueOf(long l) {final int offset = 128;if (l >= -128 && l <= 127) { // will cachereturn LongCache.cache[(int)l + offset];}return new Long(l);}
加餐部分
String intern方法
String hello=new String("he")+new String("llo");String helloTwo=hello.intern();System.out.println(helloTwo==hello);
JDK1.6
JDK1.6intern方法:變量hello調用intern方法,首先會去String常量池中找是否有hello這個常量,當發現未找到時則把堆中的hello對象的“hello”復制到String常量池,若發現String常量池中有“hello”時則會將常量池中的“hello”返回給helloTwo。
如上圖所示在JDK1.6的時候intern方法在調用后,發現未找到時則把堆中的hello對象的“hello”復制到String常量池。
JDK1.7
JDK1.7 intern方法:變量hello調用intern方法,首先會去String常量池中找是否有hello這個常量,當發現未找到時則把堆中的hello對象地址值存入到String常量池,若發現String常量池中有“hello”時則會將常量池中的“hello”返回給helloTwo。