自动拆装箱

前言

我们知道Java共有8种基本数据类型int、byte、short、long、float、double、char、boolean,对应的包装类分别为Integer、Byte、Short、Long、Float、Double、Character、Boolean。既然有了基本数据类型,那么为什么还需要包装类呢。主要因为Java是一种面向对象的语言,很多地方需要使用对象而不是基本数据类型。比如在集合类中,我们无法将int、double等类型放进去,因为集合的容器要求元素是Object类型。为了让基本数据类型也具有对象的特征,就出现了包装类型,相当于将基本数据类型"包装起来",使得基本数据类型具有对象的性质,并且为其添加了属性和方法,丰富了基本数据类型的操作。

什么是自动拆装箱

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

Java SE5之前如果要生成一个值为1的对象需要以下操作

Integer i = new Integer(1);

Java SE5之后,提供了自动拆装箱的功能,只需要以下操作

Integer i = 1;#自动装箱
int j =i;#自动拆箱

自动拆装箱的实现原理

举个例子

public class Demo {
    public static void main(String[] args) {
        Integer i = 1;
        int j = i;
    }
}

字节码如下

从以上的字节码来看,Java自动装箱调用了Integer.valueof()方法,自动拆箱调用了Integer.intValue()方法,其他包装类的自动拆装箱类似

什么时候会用到自动拆装箱

1.赋值
Integer i = 1;#自动装箱,调用 Integer.valueOf()
int j =i;#自动拆箱,调用 Integer.intValue()

2.逻辑、算术运算

Integer i = 1;
int j = 2;
int z = i + j;
Boolean flag = i > j ? true : false;

反编译后

Integer i = Integer.valueOf(1);
int j = 2;
int z = i.intValue() + j;
Boolean flag = Boolean.valueOf(i.intValue() > j);

3.将基本数据类型放到集合里面

ArrayList<Integer> list = new ArrayList<>();
list.add(1);

反编译后

ArrayList<Integer> list = new ArrayList();
list.add(Integer.valueOf(1));

4.函数调用

    public static void main(String[] args) {
        sum(2);
    }
    public static Integer sum(Integer i){
        return 0;
    }

反编译后

  public static void main(String[] args)
  {
    sum(Integer.valueOf(2));
  }
  public static Integer sum(Integer i)
  {
    return Integer.valueOf(0);
  }

自动拆装箱的问题

我们来看下面的代码

Integer i = 128;
Integer j = 128;

Integer x = 1;
Integer y = 1;
System.out.println(i==j);#false
System.out.println(x == y);#true

上面为什么会出现这样的结果,主要是由于Integer的缓存机制,我们来看一下Integer的源码

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

Integer默认的缓存范围是 -128~127,当在这一范围时,不会生成新的对象;当超过这一范围后,才生成新的Integer对象。当然缓存机制不只有Integer有,比如:

  • Boolean,缓存了true/false对应实例,确切的说,返回两个常量实例Boolean.TRUE/FALSE
  • Short,缓存了 ~128-127的数值
  • Byte,数值有限,全部被缓存
  • Character,缓存范围‘ \u0000 ' 到 ’ \u007F '

参考

https://juejin.im/post/5b8de48951882542d63b4662

https://www.cnblogs.com/dolphin0520/p/3780005.html

posted @ 2019-03-15 15:08  小永coding  阅读(783)  评论(0编辑  收藏  举报