Java基础知识-Java基本类型包装器以及自动装箱、拆箱


前言

最近在刷面试题的时候经常遇到java装箱、拆箱的题目,所以特地开此贴来讲解一下java的装箱以及拆箱机制


一、什么是基本类型包装器

众所周知,Java有8种基本数据类型,但是基本数据类型不是对象,这不和Java提出的一切皆对象不是相违背吗。其实java使用了包装器将基本数据类型进行包装成对象这样就实现了“一切皆对象”。
每一种基本数据类型的包装类如下图所示:
在这里插入图片描述
声明一个整型数据类型有两种方法:一种是使用基本数据类型,另一种就是上面介绍的包装类。代码如下:

int num = 22;//基本数据类型
Integer num = new Integer(22);//利用包装器类

二、装箱以及拆箱介绍

1.概念

装箱以及拆箱很好理解,装箱就是将基本数据类型包装成一个类,拆箱就是将一个包装类转变为基本数据类型。
在下面的这句代码中声明了一个Integer的对象num,并且将100赋值给这个对象num,在这个过程中基本数据类型num转变为Integer对象,称为装箱。

Integer num = 100;

同理,下面这句代码是将包装类型转变为基本数据类型,称为拆箱。

int num1 = num;

下面以Integer为例介绍装箱、拆箱的底层到底发生了什么。

2.装箱底层原理

以下面这句语句为例子进行说明:

Integer num= 100

在装箱过程中,底层调用的是Integer类的valueOf(int i)方法,也就是说上面的语句与下面的这条语句等价:

Integer num = Integer.valueOf(100);

valueOf方法实现如下:

   public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

可以看到是一个选择判断语句,IntegerCache是什么?接下来在进一步进行探究。IntegerCache是Integer的一个内部类,类的内容如下:

  private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            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;
        }

可以看出IntegerCache中存放了一个缓冲数组,缓冲-128 ~ 127之间的整数,-128为下界已经固定,而上界可以通过JDK的AutoBoxCacheMax参数来调整大小,默认为127。
从以上的两段源码可以知道装箱过程中如果数值在-128~127之间会返回缓冲数组中已经存在的对象的引用,如果不在-128 ~127就生成一个新的Integer对象。
同样地,在其他包装类中也是相似的结构,对应的缓冲范围如下:

  • Byte:-128 ~127
  • Short:-128 ~127
  • Long:-128 ~127
  • Character: -128 ~127

Float、Double没有缓冲,直接就是new出一个相应的对象。Byte的缓冲范围为 -128~127,而byte数据类型占一个字节即范围为-128 ~127,所以Byte永远对应的都是缓冲数组的引用。

3.拆箱底层原理

Integer num = 100;
int num1 = num;

当执行上面的代码时由于num为包装类型,而num1为基本数据类型,所以会进行自动拆箱,将包装类型转变为基本数据类型。其底层使用的方法是intValue()方法,具体内容如下:

 public int intValue() {
        return value;
    }

三、相关面试题

这里以面试题为切入点剖析java的装箱、拆箱。
声明以下变量:

Integer a=1;
Integer b=2;
Integer c=3;
Long d=2L;
Long e=3L;
int f=2;
Integer g=300;
Integer h=300;
Integer i=600;
Byte j=25;
Byte k=25;
Double m=25d;
Double n=25d;
  1. g == h
    g和h的值都是300,所以g==h为true。那你就大错特错了,这里g和h都是Integer的对象,对象之间用 “ == ”进行比较时比较的是对象的地址。由装箱的原理值300不在缓冲数组里所以都是new的对象,故地址不相同,因此,g ==h为false
  2. g == 300
    包装类型与基本数据类型进行比较的时候,触发自动拆箱,此时就是基本数据类型之间的比较,因此为true
  3. c == (a+f)
    当包装类型与基本数据类型运算的时候会触发自动拆箱。a为包装类型,f为基本数据类型,所以a拆箱变为基本数据类型1,故a+f为2,c为包装类型,包装类型与基本数据类型比较会触发自动拆箱。故为true
  4. c == (a+b)
    当包装类型与包装类型运算时会触发自动拆箱,a拆箱为基本数据类型1,b拆箱为2,故右侧的值为3,包装类型与基本数据类型比较会自动拆箱故为true。
  5. i == (g+h)
    由第四题知当包装类型与包装类型运算时会触发自动拆箱,所以最后比较的是基本数据类型之间的比较,所以为true。
  6. c.equals(a+b)
    当进行a+b的运算时会自动进行拆箱最后结果为一个基本数据类型,在equals方法中会进行自动装箱,将a+b的值包装为包装类型。java重写了equals方法,首先会判断两边包装类型是否一致,如果不一致返回false,如果一致则会判断值是否相同。这题中由于两边都是包装类Integer即包装类型相同,却数值相同故为true。
  7. e.equals(a+b)
    和第六题类型,但此时两边的包装类型不一致故返回false。
  8. b == d
    b和d都是包装类但是类型不一样,无法比较
  9. i==k
    byte的取值范围都在Byte的缓冲数组中,因此相同值的Byte比较永远返回true。
  10. n==m
    注意两边之间比较的是包装类型Double,Double没有缓冲数组是直接new的对象,即两边的地址不相同,故返回false

四、总结

  1. 包装类型与包装类型用“==”进行判断时,若在缓存数组返回true,否则返回false。注意Double、Float永远返回的是false。
  2. 用equals比较时会判断两边的包装类型是否相同,相同继续比较数值。
  3. 包装类型与包装类型或者包装类型与基本数据类型运算都会触发自动拆箱。
  4. 包装类型与基本数据类型用"=="比较会自动触发自动拆箱,转为数值类型之间的比较。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喂喂,要加油

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值