目录
- 什么是包装类
- 自动装箱和自动拆箱
- 包装类可以为null,而基本类型不可以
- 包装类型可用于泛型,而基本类型不可以
- 基本类型比包装类型更高效
- 两个包装类型的值可以相同,但却可以不相等
什么是包装类
Java的每个基本类型都有对应的包装类型,比如说int的包装类型是Integer,double的包装类型是Double。
自动装箱和自动拆箱
既然有了基本类型和包装类型,肯定有些是要在他们之间进行转换。把基本类型转换成包装类型的过程叫做装箱。反之,把包装类型转换成基本类型的过程叫做拆箱。
在Java5之前,开发人员要进行手动拆装箱
Integer integer2 = new Integer(10); |
java5引入了自动拆装箱的功能,减少了开发人员的工作
Integer chenmo = 10; // 自动装箱 |
使用反编译工作编译后的结果如下:
Integer integer3 = Integer.valueOf(10); |
也就说自动装箱是调用了Integer.valueOf()
完成的,自动拆箱是通过调用integer.intValue()
完成的。
理解了自动拆装箱的原理后,我们来看一道面试题
int a = 100; |
在看这段代码之前,我们要明白的是 == 号,基础类型比较的是值,引用类型比较的是内存地址
第一段代码,很好理解,基础类型比较的是值
第二段代码是包装类,这里需要引入一个缓冲池(IntegerCache )的概念,JVM把-128到127的数值存到了内存中,需要的时候直接从内存拿,而不是重新创建一个对象
第三段代码也很容易理解,如果-128到127是从缓冲池中拿,那么超过这个范围的,自然就是堆中创建了
第四段是基本类型和包装类型做比较,这时候包装类型会先转成基本类型,然后再比较
第五段代码同上,没有在堆中创建的对象这一步
结果即是:true、true、false、true、true
之前我们就已经知道了自动装箱是Integer.valueOf()方法,我们现在看看它的源码,如果做到-128到127是缓冲池中拿,而超过了则需要在堆中创建。
public static Integer valueOf(int i) { |
private static class IntegerCache { |
看到这里也就明白了,-128-127是如何实现的,超过这个范围为什么是在堆中创建了,在这个源码中,还有一个地方没有解释,那就是参数java.lang.Integer.IntegerCache.high
,这个参数可以加载到手动传入的值,从而扩大或者缩小缓冲池的最大值
如果我们设置这个值的大小为200:-Djava.lang.Integer.IntegerCache.high=200
,那么我们就能看到下面的代码的结果是true
Integer e = 200; |
看完上面的分析之后,我希望大家记住一点:当需要进行自动装箱时,如果数字在 -128 至 127 之间时,会直接使用缓存中的对象,而不是重新创建一个对象。
注意:缓冲池只有Integer类型有
包装类可以为null,而基本类型不可以
别小看这一点区别,它使得包装类型可以应用于 POJO 中,而基本类型则不行。
那为什么 POJO 的属性必须要用包装类型呢?
对于基本数据类型,数据库的查询结果可能是 null,如果使用基本类型的话,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值),就会抛出 NullPointerException
的异常。因为基础类型的值只能是数值。
包装类型可用于泛型,而基本类型不可以
我们先尝试定义一个List
List<int> list = new ArrayList<>(); |
报错:
Syntax error, insert "Dimensions" to complete ReferenceTypeList<Integer> list = new ArrayList<>(); |
原因是泛型只能使用Object 类及其子类,所以包装类型可用于泛型,而基本类型不可以
基本类型比包装类型更高效
基本数据类型在栈中直接存储具体的数值,而包装类型则存储在堆中,栈中存放的是引用
很显然,相对于基本数据类型而言,包装类型需要占用更多的内存空间,假如没有基本数据类型的话,对于数值这类经常能用到的数据来说,每次都要通过new来创建包装类型就显得非常笨重。
两个包装类型的值可以相同,但却可以不相等
两个包装类型的值可以相同,但却不相等
不相等是因为两个包装类型在使用“==”进行判断的时候,判断的是其指向的内存地址是否相等。包装类的值如果是在堆中创建出的话,因为内存地址不同,所以返回的是false。
而值相同是因为包装类型在做equals
比较的时候,都先拆箱成了基础类型,然后再做比较,即比较的是内容,所以为true。
public boolean equals(Object obj) { |