文章目录
- 1. 前言
- 2. Integer的缓存常量池
- 3. Integer类重写的方法
- 4. Integer的几个比较案例
- 5. 总结
1. 前言
Integer
类在对象中包装了一个基本类型 int
的值。Integer
类对象包含一个 int
类型的字段。
此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还提供了处理 int 类型时非常有用的其他一些常量和方法。
2. Integer的缓存常量池
在Integer
源码中,可以找一个一个名为IntegerCache
的私有静态内部类,这个类是用来实现Integer的缓存常量池的。
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
35
36
37
38
39// Integer类中私有的静态类 承载cache的实现 private static class IntegerCache { static final int low = -128;// 最小支持为-128 static final int high;//最大支持 static final Integer cache[];// 用来装载缓存 常量池 static { // -128~127 这个范围的整数值是使用最广泛的 int h = 127; // Java6中可以通过调整JVM启动参数来设置最大值 // 根据应用程序的实际情况 灵活的调整来提高性能 // JVM 的启动参数 -XX:AutoBoxCacheMax=size 修改最大值 String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); // 获取较大者 i = Math.max(i, 127); // 设置最大值不能超过Inter.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // 如果该值配置错误则忽略该参数配置的值,使用默认范围-128~127 } } high = h; // 初始化数组容量为127 + 128 + 1(以默认区间为参考) cache = new Integer[(high - low) + 1]; int j = low; // 缓存通过for循环来实现,创建范围内的整数对象并存储到cache数组中 // 程序第一次使用Integer的时候需要一定的额外时间来初始化该缓存 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 a=Integer.valueOf(127)
还是Integer a=127
,都会在缓存常量池中获取到提前创建好的对象。
所以只要值相同,它们获取到的对象是同一个对象,因此地址也相同。
为什么
Integer a=127
也适用呢?
像上面这样将Integer
类型的a
直接赋值给127,Java会通过自动装箱机制,将int类型转化为Integer类型。
自动装箱机制,其实也就是编译期间,编译器自动调用Integer
类中的valueOf
方法
1
2
3
4
5
6public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
查看valueOf
源码不难看出,首先会判断参数i
是否在缓存常量池的最小值low
和最大值high
之间,如果是,
就会返回常量池中的对应对象。
否则,就会创建新对象。
3. Integer类重写的方法
1
2
3
4
5
6
7public int hashCode() { return Integer.hashCode(value); } public static int hashCode(int value) { return value; }
Integer
重写了hashCode
方法,调用hashCode
方法返回值为本身对象的value。
1
2
3
4
5
6
7
8
9
10public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; } public int intValue() { return value; }
Integer
重写了equals
方法
调用equals
方法,首先会判断参数Object obj
是否是Integer
类型
如果是,则会将obj
强转成Integer
,然后取其对象中的value
,跟自己的value
进行判断。
如果不是,则返回false
4. Integer的几个比较案例
两个Integer对象进行比较
1
2
3
4
5
6public static void main(String[] args) { Integer a = new Integer(66); Integer b = new Integer(66); System.out.println(a == b); }
因为a和b均为新new出来的对象,并且==
比较的是地址,两个new出来的对象永远不可能相等,因此输出false
两个Integer对象使用equal方法进行比较
1
2
3
4
5
6public static void main(String[] args) { Integer a = new Integer(66); Integer b = new Integer(66); System.out.println(a.equals(b)); }
上面有说过使用equal
方法,如果两个比较的对象均为Integer
,则比较它们的value
是否相等,很明显,它们的value
相等,所以是true
。
基本类型和Integer类型 通过 == 比较
1
2
3
4
5
6public static void main(String[] args) { Integer a = new Integer(66); int b = 100; System.out.println(a == b); }
这里,基本类型和Integer
类型比较,Java会先自动进行拆箱操作,也就是将包装类型转化为基本类型,然后再进行比较,所以比较的是两个int值是否相同,答案是true
在缓存范围内的比较
1
2
3
4
5
6public static void main(String[] args) { Integer a = 66; Integer b = 66; System.out.println(a == b); }
对于这种直接将两个int
类型赋值给Integer
,Java会先进行自动装箱,也就是调用valueOf
方法。
由于66在[-127,128]范围内,也就是默认的缓存范围,所以这里不会新创Integer
对象,而是生成的对象引用都会指向Integer内部的常量池中对应的值的对象。所以两个对象为同一对象。因此答案是true
。
在缓存范围外的比较
1
2
3
4
5
6public static void main(String[] args) { Integer a = 128; Integer b = 128; System.out.println(a == b); }
同样的,Java会进行装箱操作,但是由于值不在[-127, 128]范围内,因此valueOf
方法会返回一个new Integer(i);
,因此两个对象并不是指向常量池对应的值的对象,故不是同一对象。答案是false
new生成的Integer对象与直接赋值的Integer对象的比较
1
2
3
4
5
6
7public static void main(String[] args) { Integer a = new Integer(66); Integer b = 66; System.out.println(a == b); System.out.println(a.equals(b)); }
首先,a是new出来的对象,而b是指向Integer内部的常量池中对应的值的对象。
两者明显不是一个对象,只是两个对象的value相同而已。
所以答案是false
和true
5. 总结
首先,不仅仅是Integer
类型有缓存常量池这个说法。
Byte,Short,Integer,Long,Character都有缓存常量池。
- Byte,Short,Integer,Long为 缓存范围 -128 到 127
- Character缓存范围为 0 到 127
- 只有Integer缓存范围可以改变
其次,开发中应该尽量避免多次装箱开箱操作。
int值直接存放于内存栈中,虽然数值操作不是原子性的,但是在单线程的存取操作中,开销小,所以速度快很多,不像Integer**,还需要牵扯对象头的内存存储以及其他操作,更加的消耗性能**。
最后
以上就是热情蛋挞最近收集整理的关于【JavaSE】深入理解Integer缓存原理1. 前言2. Integer的缓存常量池3. Integer类重写的方法4. Integer的几个比较案例5. 总结的全部内容,更多相关【JavaSE】深入理解Integer缓存原理1.内容请搜索靠谱客的其他文章。
发表评论 取消回复