在讲解128陷阱之前,需要了解一些概念。
包装器类型
Java是面向对象的语言,但基本类型并不是面向对象的,从而出现了包装器类型,并且包装器添加了更多的属性和方法。如我们在使用集合类型Collection的时候就一定要使用包装类型而非基本类型,它相当于将基本类型"包装起来",使它具有了对象的性质,丰富了基本类型的操作。
包装器类包括Integer、Long、Float、Double、Short、 Byte、Character和Boolean
前6 个类派生于公共的超类Number。
包装器类是不可变的,即一旦构造了包装器,就不允许更改包装在其中的值。同时,包装器类还是final,因此不能派生它们的子类。
自动装箱器
自动将基本数据类型转换为包装器类型。
通过查看Integer.valueOf()方法源码,可以看到这个方法就是将int基本类型转换为Integer包装类型的方法,这个就是自动装箱的底层原理。
自动体现在,例如下图,创建了一个ArrayList对象, 因为在添加时会将int类型自动转换成Integer类型,arrayList.add(c)实际上是执行了 arrayList.add(Integer.valueOf(c))
自动拆箱器
自动将包装器类型转换为基本数据类型。
拆箱过程是通过调用包装器的 xxxValue方法实现的(xxx代表对应的基本数据类型)
当把一个Integet对象赋给一个int值时,并不会报错,原因就是在复制给int基本类型时,会自动执行拆箱操作,也就是 int d = arrayList.get(0).intValue();
输出结果为2.
自动拆装箱与缓存
(这里以Integer为例)
看到上面这个代码时,可以先思考一下输出结果到底是什么。
我们可能会认为上面的两个判断的结果都是false。
虽然比较的值是相等的,但是由于比较的是对象,而对象的引用不一样,所以会认为两个是false的。
但其实并不是这样的,输出的结果第一个是true,这就和Integer中的缓存机制有关,也是传说中的128陷阱
在Integer的valueOf()方中,当数值在-128-127之间时,数值都存储在一个cache数组中,该数组相当于一个缓存,当我们在-128-127之间进行自动装箱的时候,我们就直接返回该值在内存当中的地址,所以在-128-127之间的数值用==进行比较是相等的,因为判断的都是同一个对象的地址。而但如果不在这个区间的数,则需要新开辟一个内存空间,比较的就不是同一个对象,所以不相等。
如果是new一个对象时,则不会出现这种情况。
在别的包装类中,也有缓存技术。
包装类型 | 基本数据类型 | 缓存对象(基本数据类型值) |
---|---|---|
Boolean | boolean | true,false(全部值) |
Byte | byte | -128~127(全部值) |
Short | short | -128~127 |
Character | char | 0~127 |
Integer | int | -128~127(默认为127) |
Long | long | -128~127 |
Float | float | 无缓存值 |
Double | double | 无缓存值 |