java的装箱、拆箱

从Integer出发,理解java的装箱、拆箱机制。 楼主遇到一个问题

1
2
3
4
5
6
Integer m = 1;
Integer n = 1;
System.out.println(m==n);
Integer p = 1000;
Integer q = 1000;
System.out.println(p==q);

答案是: true false 为什么会出现这种结果呢,就是因为 java 的装箱和拆箱机制,且听楼主慢慢道来。

**注:全篇使用 JDK 1.7 **

1==1 but 1000!=1000

查阅了一些资料,发现当 Integer 在 [-128, 127](闭区间)之间时,temp1==temp2,不在此区间时 temp1!=temp2,源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* @author knight
* @createtime : 下午1:16:15
* @description :
* @result :
*/
public class IntegerEqualQuestion{
public static void main(String[] args){
int start = -129;
int end = 128;
Integer temp1;
Integer temp2;
for(int i=start; i<=end; i++){
temp1 = i;
temp2 = i;
System.out.println("new Integer(" + i + "):" + (temp1==temp2));
}
}

}

运行 IntegerEqualQuestion main

Alt text

Alt text

一眼看不出装箱、拆箱的痕迹,看看编译器有没有做什么手脚 使用 javac 编译上述文件 把编译后的 .class 文件与 .java 文件对比

Alt text

发现原来的直接赋值被替换成了 Integer.valueOf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
//断言 high>=127
assert IntegerCache.high >= 127;
//判断传入参数 i 是否在范围之间
//如果是,返回 IntegerCache.cache 数组中索引为 i + (-IntegerCache.low) 的元素
//如果不是,返回一个新的 Integer 对像
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private static class IntegerCache {
//low定义为-128
static final int low = -128;
static final int high;
//定义一个 cache 数组
static final Integer cache[];

static {
// high value may be configured by property
int h = 127;
//大概是从 jvm 中取出Integer对象缓冲池的high值,没有仔细研究
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low));
}
//给high赋值
high = h;

//创建数组对象赋值给 cache
//大小为 (high-low)+1
//类型为 Integer
cache = new Integer[(high - low) + 1];
int j = low;
//给 cache 中的元素赋值,满足 cache[i]=i+low
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}

private IntegerCache() {}
}

延伸:探究 sun.misc.VM.getSavedProperty(“java.lang.Integer.IntegerCache.high”);

发现这个值是可以通过 jvm 参数设置的,默认是 127,如下可以将这个值设置为200

1
-Djava.lang.Integer.IntegerCache.high=200

运行 IntegerEqualQuestion main

Alt text

结论:

当使用 Integer a = b; b为一个int类型的数据创建一个 Integer 时 如果 b 满足 b<=high && b>=low (默认 high=127,low=-128,可以设置 high 的值),返回 cache[b+high] 如果 b 不满足上述条件,返回一个新的 Integer 所以,

有 Integer m=1; Integer n=1; 时 m==n;
此时m、n 都是 cache[1+high]


有 Integer p=1000; Integer q=1000; 时 p!=q; 此时 p 是一个新创建的 Integer 对象,q 是一个新创建的 Integer 对象

简单的流程图

Alt text

|