大家好,我是孤焰。今天要谈一谈在面试过程中可能被面试官提到的一个问题——Java的自动拆箱装箱与缓存机制?
由于我也是刚刚学习编程的小白,所以此篇博文将参考了多篇博文,最后总结而成。
最近由于多门考试临近,所以博文更新速度可能会慢一些,希望大家谅解。
1.基本类型与包装类型
我们知道,Java有8大基本数据类型,分别为byte 、short、int、long、float、double、char、boolean。
我们在实际开发中,除了使用到数据的值之外,还会涉及到对数据的操作。根据“面向对象”编程的思想,这些常见的操作被抽象成方法,封装到了一个类中,一个基本数据类型对应一个这样的类,这些类统称为“包装类”。
8大基本类型 分别对应 8个包装类,再加上两个用于高精度运算的包装类,共有10大包装类。分别为:
- Byte:对应byte类型
- Short:对应short类型
- Integer:对应int类型
- Long:对应long类型
- Float:对应float类型
- Double:对应double类型
- Character:对应char类型
- Boolean:对应boolean类型
- BigInteger:支持任意精度[长度]的整数运算。
- BigDecmail:支持任意精度的浮点数运算,主要用于金额计算。
包装类的好处:它提供了一系列操作本类型数据的方法,可以为我们在开发过程中操作8大基本类型数据提供充足的“工具”。
2.自动拆箱与装箱
1)装箱
把基本数据类型转换成包装类的过程就是装箱。
2)拆箱
反之,把包装类转换成基本数据类型的过程就是拆箱。
3)自动拆装箱
自动装箱:就是将基本数据类型自动转换成对应的包装类。
自动拆箱:就是将包装类自动转换成对应的基本数据类型。
3.自动拆装箱带来的问题
1)包装对象的数值比较,不能简单的使用==,虽然-128到127之间的数字可以[下文中解释],但是这个范围之外还是需要使用equals比较。【== 比较的是地址,equals比较的是值】
2)由于自动拆箱,如果包装类对象为null,那么自动拆箱时就有可能抛出NPE[null pointer exception]。
3)如果在一个for循环中有大量拆装箱操作,会浪费很多资源。
4.Integer的缓存机制
首先,看一个例子:
public class Main {
public static void main(String[] args) {
Integer a = 3; //整数3自动装箱
Integer b = 3; //整数3自动装箱
System.out.println(a == b); //true
Integer c = 128; //整数128自动装箱
Integer d = 128; //整数128自动装箱
System.out.println(c == d); //false
}
}
上述代码的运行结果如下图:
也就是说:整数3自动装箱后赋值给a、b两个引用变量,这两个引用指向的是同一个对象。但是整数128自动装箱后赋值给c、d两个引用变量,这两个引用指向的是不同对象。
那么问题来了——都是自动装箱,为什么不同数值自动装箱的结果不一样呢?——这是由于Integer的缓存机制导致的。
4.1 为什么要实现缓存机制
在实际开发过程中,会经常在不经意间就触发了自动拆装箱机制。我们知道,自动装箱会创建一个包装类对象,一套程序跑下来,会生成多少个这样的对象?那开销得多大啊。
因此,出于节省内存和提高性能的目的,从Java5开始,为我们提供了Integer的缓存机制。
4.2 缓存机制的范围
Integer缓存数组中默认保存了 -128~127的值的包装类对象。其中后面的127数值可以通过JVM参数 -XX:AutoBoxCacheMax=size(size为填写的大小) 修改【这也是JVM调优的一个常用配置项】。
注意:调整JVM参数-XX:AutoBoxCacheMax=size,最大缓存值可以达到-128—size,只能调整上限,这和Integer缓存算法实现有关,当然这个参数只对Integer有效,Long…无法调节。
4.3 所有包装类的缓存范围总结
包装器的缓存:
- Boolean:(全部缓存)
- Byte:(全部缓存)
- Character:(0 — 127缓存)
- Short:(-128 — 127缓存)
- Long:(-128 — 127缓存)
- Integer:(-128 — 127缓存)
- Float:(没有缓存)
- Doulbe:(没有缓存)
5.最后
都看到最后了,求求大家点个赞再走吧!你的支持是博主创作的最大动力。