本篇文章先从一道题目开始
题目内容
int a = 100;
Integer b = 100;
System.out.println(a == b); // true
Integer a1 = 101;
Integer b1 = 101;
System.out.println(a1 == b1); // true
Integer a2 = 200;
Integer b2 = 200;
System.out.println(a2 == b2); // false
以上的结果是否和你预期的一一致呢?如果都能正确的回答,说明对java的自动拆装箱和整数的缓存池有了一定的了解。
自动拆装箱,说的通俗易懂点就是基本类型和其包装类之间的相互转换
类型 | 类型转换 | 实现方法 |
---|---|---|
装箱 | int 转 Integer | Integer x = Integer.valueOf(int value) |
拆箱 | Integer 转 int | int y = x.intValue() |
关于int 和 Integer之间的比较,Integer和Integer之间的比较,先看一下比较规则
比较规则
类型比较 | 比较规则 |
---|---|
int 和 int | == 比较的是值、无法使用equals比较 |
int 和 Integer | 基本类型和包装类型, 会进行自动拆箱转为基础类型进行比较 |
Integer 和 Integer | ==比较的是引用地址、equals比较的是值 |
在Integer 和 Integer 比较时,使用==比较的是引用地址,那么久涉及常量池(IntegerCache)的问题,分以下两种情况
1、 是否使用常量池
- new Integer()构造方法, 不使用缓存池
- Integer.valueOf()方法, 使用缓存池
2、大小是否在IntegerCache范围内
- 在【-128 ~127】范围内,使用缓存池
- 在【-128 ~127】范围外,不使用缓存池
看一下Integer的源码可知,IntegerCache是Integer的静态内部类
当使用valueOf()创建一个Integer时,
在[IntegerCache.low,IntegerCache.hign]闭区间范围内的,使用缓存池
否则使用new Integer(i)创建一个新的对象
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=-128; IntegerCache.high =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 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() {}
}
代码大致的内容:
读取java.lang.Integer.IntegerCache.high变量的值,如果不为空,和127比较大小Math.max(i, 127),将上限设置为两个中的最大值
然后初始化一个Integer数组,[-128, -127, -126, -125, -124,… 124, 125, 126, 127]
其中new Integer(j++) 是先赋值,再加一
基于以上的结论和认识,尝试做一下下面的比较
示例一
Integer a3 = new Integer(121);
Integer b3 = new Integer(121);
System.out.println(a3 == b3); // false
System.out.println(a3.equals(b3)); // true
Integer a4 = new Integer(300);
Integer b4 = new Integer(300);
System.out.println(a4 == b4); // false
System.out.println(a4.equals(b4)); // true
示例一解读:
首先new Integer()构造方法, 不使用缓存池,所以无需考虑范围
==比较的是引用地址,创建了两个对象,所以是false
equals比较的是值,所以是true
很多人好奇为什么equale比较的是值,这个可以看一下Integer的源码
示例二
Integer a5 = Integer.valueOf(122);
Integer b5 = Integer.valueOf(122);
System.out.println(a5 == b5); // true
System.out.println(a5.equals(b5)); // true
Integer a6 = Integer.valueOf(500);
Integer b6 = Integer.valueOf(500);
System.out.println(a6 == b6); // false
System.out.println(a6.equals(b6)); // true
示例二解读:
Integer.valueOf()方法, 使用缓存池,使用缓存池,就需要看大小是否在IntegerCache范围内,122在缓存池范围内,500不再缓存池范围内
==比较的是引用地址,使用缓存池创建的a5和b5,实际上是同一个对象,所以是true,a6和b6的大小不再范围内,不适用缓存池,所以创建了两个对象,所以是fasle
equals比较的是值,所以是true
示例三
Integer a7 = Integer.valueOf(133);
Integer b7 = new Integer(133);
System.out.println(a7 == b7); // false
System.out.println(a7.equals(b7)); // true
示例三解读:
Integer.valueOf() 方法使用缓存池,且133在【-128 ~127】范围内,a7变量指向常量池中的133
new Integer() 构造方法不使用缓存池,b7指向堆内存中的133对象,两个对象不是同一个,所以a7 == b为false
equals比较的是值,所以是true
如果对以上的还有疑惑,重新看上面的比较规则;