Java 有8种基本类型:byte/short/int/long/float/double/char/boolean,对应有8种包装类:Byte/Short/Integer/Long/Float/Double/Character/Boolean。
- 一、Integer 的缓存机制
- 二、拆箱与装箱
- 三、int 与 Integer 的使用场景
下面以 int 与 Integer 为例,说明一些细节点。
一、Integer 的缓存机制
// 1. 默认缓存范围 -128~127
System.out.println(Integer.valueOf(127) == Integer.valueOf(127)); // true
System.out.println(Integer.valueOf(128) == Integer.valueOf(128)); // false
// 2. 指定缓存范围最大值 -XX:AutoBoxCacheMax=128,-128~128
System.out.println(Integer.valueOf(128) == Integer.valueOf(128)); // true
System.out.println(Integer.valueOf(129) == Integer.valueOf(129)); // false
System.out.println("====== end ======");
- Integer 默认缓存的 int 范围是 [-128, 127],此范围内的值使用
享元模式
,即只保留一份,例如 1 这个数字,存储在 IntegerCache 中,每次获取,取到的都是同一个 Integer 对象- 缓存的最大值可以通过
-XX:AutoBoxCacheMax=highValue
来指定- 缓存范围内的值可以使用 == 来判断相等,因为是同一个 Integer,缓存范围之外的需要使用 equals 进行相等判断,Integer#equals 内部实际上比较包装的 int value
- 使用
Integer.valueOf
可以使用到缓存,使用new Integer
每次都会创建新的对象,不会使用缓存,所以尽量使用 Integer.valueOf
public final class Integer extends Number implements Comparable<Integer> {
// 包装的 int 对象
private final int value;
public static Integer valueOf(int i) {
// 从缓存范围获取数据,缓存范围之外的直接 new
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
public boolean equals(Object obj) {
if (obj instanceof Integer) {
// equals 比较 int value
return value == ((Integer)obj).intValue();
}
return false;
}
// 缓存类
private static class IntegerCache {
static final int low = -128; // 最小值
static final int high; // 最大值
static final Integer cache[]; // 缓存结果集
static {
// high 可以通过 -XX:AutoBoxCacheMax=<highValue>来指定
int h = 127;
// 1. 获取 high
String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
...
}
high = h;
// 2. 创建缓存器,并初始化 Integer 对象到其中
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;
}
}
}
二、拆箱与装箱
- 装箱与拆箱是编译器来做的,装箱代码
Integer x = 1
,编译器会编译为Integer x = Integer.valueOf(1)
;拆箱代码int y = x
,编译器会编译为int y = x.intValue()
;- 由于装箱使用了
Integer.valueOf
,所以也会走缓存
Integer x = 1; // 自动装箱
int y = x; // 自动拆箱
字节码:
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
6: invokevirtual #3 // Method java/lang/Integer.intValue:()I
三、int 与 Integer 的使用场景
- 对于性能极其敏感的情况下,使用 int 可以避免创建对象,不仅节省创建对象的时间,还节省内存,因为一个对象的话会有额外的对象头和补齐填充;
- int[] 占用连续内空间,Integer[] 不是,所以 int[] 操作起来更高效。
问题:
- int 存放在哪里?是否有内存安全问题?
网友评论