java容器自动装箱_自动拆箱与装箱

概念

在说到拆箱和装箱之前,需要了解Java中有八种基本的数据类型,分别是:byte、short、char、int、long、float、double和boolean。这八种基本类型在Java中都有对应的包装类型:Byte、Short、Character、Integer、Long、Float、Double以及Boolean。

有了基本类型为什么还需要包装类型呢?因为 Java 是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。比如,在集合类中,我们是无法将 int 、double 等类型放进去的。因为集合的容器要求元素是 Object 类型。为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。

自动拆装箱(1.5引入)

什么是自动拆、装箱?

自动装箱:就是将基本数据类型自动转换成对应的包装类

自动拆箱:就是将包装类自动转换成对应的基本数据类型

自动拆装箱有什么好处

方便

基本类型和包装类型转换无需手动编码实现,由编译器帮我们完成

节省空间

大部分包装类型都会有缓存的存在,缓存一定范围大小的数据。如果是在范围内大小,则直接返回缓存内的对象,而不新建。节省的存储空间

自动装箱与自动拆箱的实现原理

自动装箱都是通过包装类的 valueOf() 方法来实现的,自动拆箱都是通过包装类对象的 xxxValue() 来实现的

如有以下代码:

public static void main(String[] args) {

Integer a = 1;

int b = a;

}

进行反编译后的代码如下:

public static void main(String[] args) {

Integer a = Integer.valueOf((int)1);

int b = a.intValue();

}

从上面反编译后的代码可以看出,int 的自动装箱是通过 Integer.valueOf() 方法来实现的。Integer 的自动拆箱是通过 integer.intValue 来实现的。

如果将八种类型都反编译一遍就会发现上面说的规律:装箱valueOf(),拆箱XXXValue

自动拆装箱带来的问题

==比较问题

public static void main(String[] args) {

Integer a = 100;

Integer b = 100;

Integer c = 200;

Integer d = 200;

Integer e = new Integer(100);

Integer f = Integer.valueOf(100);

System.out.println(a == b);

System.out.println(c == d);

System.out.println(a == e);

System.out.println(a == f);

}

上面代码运行后输出:

true

false

false

true

由于自动装箱机制,在一定数值范围内返回的是同一个对象,在==比较时为true。但如果未命中缓存则会为false。所以比较时应该使用equals或先转成基本类型在进行

空指针问题

自动拆箱时返回的是包装对象里 的xxxValue的值,如果包装类型为null,那么在拆箱的时候就会抛NPE

public static void main(String[] args) {

Integer a = null;

int b = a;

}

循环内自动装箱问题

public static void main(String[] args) {

Integer num = 0;

for (int i = 0; i < 5000; i++) {

num += 1;

}

}

反编译后代码:

public static void main(String[] args) {

Integer num = Integer.valueOf((int)0);

for (int i = 0; i < 5000; ++i) {

num = Integer.valueOf((int)(num.intValue() + 1));

}

}

在循环中自动装箱,相当于循环内创建对象,会造成大量的对象产生,浪费系统资源同时加重垃圾回收的工作。

再回到上面 ==比较问题 中的代码:

public static void main(String[] args) {

Integer a = 100;

Integer b = 100;

Integer c = 200;

Integer d = 200;

System.out.println(a == b);

System.out.println(c == d);

}

实际执行结果 a = b 和 c != d。原因就和 Integer 中的缓存机制有关。在JDK1.5中引入缓存来节省使用包装类时内存和提高性能。实现原理是在包装内部有一个静态内部类,在内部类加载时会先创建好一定范围内的对象存到一个数组里。在调用valueOf时,在判断是不是在缓存范围内,如果是直接返回缓存数组里的,否则再新建一个对象。

缓存在第一次使用时被初始化。大小可以由JVM参数-XX:AutoBoxCacheMax=size来指定。JVM初始化时此值被设置成java.lang.Integer.IntegerCache.high属性并作为私有的系统属性保存在sun.misc.vm.class中。

缓存的范围

如果一个变量p的值是:

-128至127之间的整数(§3.10.1)

true 和 false的布尔值 (§3.10.3)

‘\u0000’至 ‘\u007f’之间的字符(§3.10.4)

将p包装成a和b两个对象时,可以直接使用a==b判断a和b的值是否相等。也就是这个范围中的值会使用缓存

缓存的对象

有ByteCache用于缓存Byte对象 有固定范围: -128 到 127

有ShortCache用于缓存Short对象 有固定范围: -128 到 127

有LongCache用于缓存Long对象 有固定范围: -128 到 127

有CharacterCache用于缓存Character对象 范围是 0 到 127

缓存行为不仅适用于Integer对象。针对所有的整数类型的类都有类似的缓存机制

其它约束

除了Integer以外,缓存范围都不能改变

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值