一:在认识 “128陷阱” 之前,首先来了解一下包装类:
- 定义:万物皆对象。将基本数据类型包装成对象的类
- 基本数据类型不是包装类的简写形式
- 基本数据类型的包装类
4.自动拆装箱:基本数据类型 包装类 byte Byte char Character short Short int Integer long Long float Float double Double boolean Boolean - 自动装箱:基本数据类型直接转换成引用类型
int a = 10; //会编译成 Integer b = Integer.valueOf(10); Integer b = a; //自动装箱操作
- 自动拆箱:引用类型转换为基本数据类型
- 包装类和基本数据类型会自动拆箱
Integer a = 10; //会编译成:int b = a.intValue(); int b = a; //自动拆箱操作
- 包装类和基本数据类型会自动拆箱
- 自动装箱:基本数据类型直接转换成引用类型
二:Integer 中的 == 判断
你是否遇到过以下场景:
Integer a = 128;
Integer b = 128;
int c = 128;
int d = 128;
System.out.println(a == b); // false
System.out.println(c == d); // true
- 在 Java 中 int 类型是基本数据类型,== 比较的是值的信息
- Integer 类型是包装类型,在包装类中 == 判断的是对象的地址
三:Integer 在 Java 中的缓存机制:
在 Java 中为了节省内存,对 Integer 类型做了缓存:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int 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_VALUE
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++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
- 在类加载过程中,会在堆中创建 -128 ~ 127 范围的 Integer 类型数组
- 当创建对象时,值在 -128 ~ 127 之间会放回 Integer 数组中值对应位置的地址
- 如果超出这个范围就会在堆内存中开辟一块新的 Integer 对象存储这个值
四:"128 陷阱"
- "128 陷阱" 就是由于 Integer 类型在堆内存中有 -128 ~ 127 范围内的缓存
- 当超出这个范围的 Integer 类型的对象相比较与预期结果会不同
五:如何避免 "128 陷阱"
- == 方式:无法避免
- 基本数据类型判断的是值相等
- 引用类型判断的是地址是否相等
- Integer 类型数据 == int 类型数据会涉及到自动拆箱操作,判断值是否相等
Integer a = 10; int b = 10; System.out.println(a == b); // true //因为 a 会进行拆箱操作,再进行值得对比
- equals() 方法:可以避免
- 在 Object 类当中 equals() 方法判断的是两个引用类型的地址是否一致,但是很多类都将 equals() 方法进行了重写
- 在 Integer 类型中,对父类的 equals() 方法进行了重写
- 当调用重写后的 equals() 方法时,需要传入一个 Integer 类型的参数,如果传入的是整形,会进行装箱操作进行传值。
- 进入到方法中,又会把两个 Integer 类型的数据进行拆箱操作
- 将两个值转为 int 类型进行比较返回
- Integer 类型中 equals() 比较不涉及到地址,只涉及到它们拆箱后的值
Integer a = new Integer(127); Integer b = new Integer(127); System.out.println(a.equals(b)); // true