的
Android
看的有點頭暈,換個口味,下一篇再更
Surface
偶然網上看到如下代碼:
public class IntegerTest {
private Integer a = 100;
private Integer b = 100;
private Integer c = 200;
private Integer d = 200;
public static void main(String[] args) {
new IntegerTest().test();
}
public void test(){
System.out.println(a==b);
System.out.println(c==d);
}
}
輸出結果如下:
true // 表明 a 和 b 是同一個對象
false // 表明 c 和 d 不是同一個對象
大家可能已經知道這是關于
Java
整數對象緩存(-128–127)的問題。
我們看下到底為什麼會這樣
反彙編 class
檔案
class
通過
javap -c
指令将
class
檔案進行反彙編,内容如下:
public class hua.lee.test.IntegerTest {
// 此處是編譯後生成的對象初始化方法
public hua.lee.test.IntegerTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 100
7: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
10: putfield #3 // Field a:Ljava/lang/Integer;
13: aload_0
14: bipush 100
16: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
19: putfield #4 // Field b:Ljava/lang/Integer;
22: aload_0
23: sipush 200
26: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
29: putfield #5 // Field c:Ljava/lang/Integer;
32: aload_0
33: sipush 200
36: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
39: putfield #6 // Field d:Ljava/lang/Integer;
42: return
... // 省略部分
}
以變量
a
為例,它的核心指派部分是:
4: aload_0
5: bipush 100
7: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
10: putfield #3 // Field a:Ljava/lang/Integer;
invokestatic
是執行一個靜态方法的指令,這裡執行的是
Integer.valueOf()
,也就是說
的自動裝箱其實就是編譯器編譯時将
Java
轉換為
Integer a = 100;
的操作
Integer a = Integer.valueOf(100);
Integer.valueOf()
Integer.valueOf()
Integer.valueOf()
的實作如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
可以看到
- 當傳入的數值在
和IntegerCache.low
之間的話,會傳回IntegerCache.high
數組中的IntegerCache.cache
對象Integer
- 否則,
new Integer()
IntegerCache
是
Integer
的内部類,代碼如下:
private static class IntegerCache {
// low 是寫死的
static final int low = -128;
// 關于high,看樣子是可以動态調整
static final int high;
// 用來緩存 Integer 對象的集合
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
// 從 java.lang.Integer.IntegerCache.high 屬性中讀取緩存的上限
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
// 屬性不為空,進行數值轉換處理
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
// 不能小于 127
i = Math.max(i, 127);
// 确定數組上限
h = 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++);
// assert 保證上限 >= 127
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
關于
Integer
的緩存問題我們就分析完了
-
緩存的下限是固定的Integer
-128
-
緩存的上限可以通過Integer
設定,但是必須java.lang.Integer.IntegerCache.high
>=127
-
在類初始化的時候就把緩存集合Integer
建立好了,并且在類初始化時會将cahce
集合填充完成cahce