开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
Integer 面试中我们经常被问到,另外工作中我们也经常遇到Integer的比较,所以今天来快速总结下这个知识点。
1. Integer i=200; 会发生什么?
首先我们假设声明了两个局部变量:
java Integer i=200; Integer j=100;
事实上,Java最终的逻辑是不管你后边的数是多少,最终都会调 Integer.valueOf(i);
来将给定的数值,进行 装箱 操作,但是里边会判断,就是如果给定数值 i
- 是在-127-128之间的数值,那么将会从一个Integer类型的缓存数组中 拿到指定位置(即index是给定数值的)对应的Integer对象, 如果给定数值
i
不在 -127-128范围内,那么 - 将会在堆上开辟空间,new一个Integer对象出来
空口无凭,我们使用命令反汇编一下,看看到底是是不是会像上边说的那样; 执行命令:
Javap -p -v -c target/test-classes/com/xzll/test/mianshi/IntegerCacheTest.class
结果如下:
2. IntegerCache初始化源码&&valueOf简析
我们看下这个逻辑,Integer类源码如下:
```java public final class Integer extends Number implements Comparable { private static class IntegerCache { //下界 static final int low = -128; //上界,可通过 -XX:AutoBoxCacheMax=size 来调整大小,但是不能超过Inter.MAX,并且小于127的话,就还是取127 static final int high; //这个就是存储Integer对象的数组了 static final Integer[] cache; static Integer[] archivedCache;
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
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;
// Load IntegerCache.archivedCache from archive, if possible
VM.initializeFromArchive(IntegerCache.class);
int size = (high - low) + 1;
// Use the archived cache if it exists and is large enough
// 新建一个Integer数组,初始值为-128, -127, ..., 0, 1, 2, ..., 127
if (archivedCache == null || size > archivedCache.length) {
Integer[] c = new Integer[size];
int j = low;
for(int k = 0; k < c.length; k++)
c[k] = new Integer(j++);
//赋值给 archivedCache变量
archivedCache = c;
}
//赋值给 cache变量
cache = archivedCache;
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)];//不new object,而是直接从cache中读出object返回 return new Integer(i);//new 一个Integer对象返回 }
} ```
上边代码比较简单,我们不过多展开了
3. 演示一下各种对比以及结果:
```java public static void main(String[] args) {
int i1 = 200; Integer i2 = 200; System.out.println("i1 == i2:结果:" + (i1 == i2) + ",// int和new出来的Integer (因为200不在(-127-128)区间,所以会new对象 )比较,i2会自动拆箱 所以会变成两个int的比较");
Integer i3 = 200;//编译后,此处变为 -> Integer i3 = Integer.valueOf(200); 也就是说不会从IntegerCache中获取,而是new了一个对象 Integer i4 = 200; System.out.println("i3 == i4:结果:" + (i3 == i4) + ",// 由于200不在缓存 -127-128之间,所以此处是两个对象的比较,i3内存地址:" + System.identityHashCode(i3) + " ,i4内存地址:" + System.identityHashCode(i4));
Integer i15 = new Integer(100); Integer i16 = new Integer(100); System.out.println("i15 == i16:结果:" + (i15 == i16) + ",// i15和i16是new的两个对象,i15内存地址:" + System.identityHashCode(i15) + " ,i16内存地址:" + System.identityHashCode(i16));
Integer i17 = 100; System.out.println("i15 == i17:结果:" + (i15 == i17) + ",// 由于 i15是new的对象,i17是从Integer缓存数组中拿的对象,两个都是对象,i15内存地址:"+System.identityHashCode(i15)+",i17内存地址:"+System.identityHashCode(i17));
Integer i18 = 100; System.out.println("i17 == i18:"+"结果:" + (i17 == i18) + ",// 由于100 在缓存 -127-128之间,所以此处是两个相同对象的比较(因为都是从数组中拿的同一个index位置的Integer对象),i17内存地址:" + System.identityHashCode(i17) + " ,i18内存地址:" + System.identityHashCode(i18));
int i100=100; System.out.println("i5==i100:结果:"+(i15==i100)+",// 由于i100是基础类型,和从Integer缓存中拿出来的i17(Integer对象比较)比较,i17会自动拆箱,结果自然是true"); } ```
输出:
i1 == i2:结果:true,// int和new出来的Integer (因为200不在(-127-128)区间,所以会new对象 )比较,i2会自动拆箱 所以会变成两个int的比较 i3 == i4:结果:false,// 由于200不在缓存 -127-128之间,所以此处是两个对象的比较,i3内存地址:706197430 ,i4内存地址:1325808650 i15 == i16:结果:false,// i15和i16是new的两个对象,i15内存地址:510464020 ,i16内存地址:1987083830 i15 == i17:结果:false,// 由于 i15是new的对象,i17是从Integer缓存数组中拿的对象,两个都是对象,i15内存地址:510464020,i17内存地址:1632492873 i17 == i18:结果:true,// 由于100 在缓存 -127-128之间,所以此处是两个相同对象的比较(因为都是从数组中拿的同一个index位置的Integer对象),i17内存地址:1632492873 ,i18内存地址:1632492873 i5==i100:结果:true,// 由于i100是基础类型,和从Integer缓存中拿出来的i17(Integer对象比较)比较,i17会自动拆箱,结果自然是true
(idea运行)附图如下:
3.1 做个小总结
- 无论如何,Integer i=xxx; 与new Integer(xxx) 不会相等。不会经历拆箱过程
- 两个都是非new出来的Integer对象(即Integer i=xxx ),如果xxx 在-128到127之间,则是true,否则为false
- 两个都是new出来的,都为false
- int和Integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比
4. 事实上,不仅Integer这么做,其他也有类似做法,如下
- 有 ByteCache 用于缓存 Byte 对象
- 有 ShortCache 用于缓存 Short 对象
- 有 LongCache 用于缓存 Long 对象
- 有 CharacterCache 用于缓存 Character 对象
Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行。
可以看出来jdk的大佬们是多么的追求极致!
一天一小步,一年一大步!
ps:今晚是通宵上线的一晚,请bug远离我~~~