JavaSE的自动装箱和自动拆箱

标签: java java se
656人阅读 评论(0) 收藏 举报
分类:

回顾一下Java基础数据类型:

Java数据类型

基础类型 字节 包装类型
int 4字节 Integer
byte 1字节 Byte
short 2字节 Short
long 8字节 Long
float 4字节 Float
double 8字节 Double
char 2字节 Character
boolean 未定 Boolean

Java属于面向对象语言那么为什么会出现非对象类型数据(基础类型),因为基础数据类型是的虚拟机的运行速度更快而且占用内存更少。详情内容可以参见:Java为什么需要保留基本数据类型

为什么要有装箱&拆箱

在JavaSE5之前我们创建爱你Integer对象:

Integer i = new Integer(10);

从JavaSE5提供了自动装箱的特性时,我们可以更简单的创建基础类型的对象:

Integer a = 10;
int b = a;

从上面的代码我们可以简单的看出装箱、拆箱的操作:
Integer a = 10; 我们将10【装箱】生成Integer对象。
int b = a; 我们将Integer【拆箱】转成int基础类型

装箱和拆箱是如何实现的

我们这里先写一个简单的类,然后反编译看看它的字节码文件

public class Main {
    public static void main(String[] args) {
        Integer a = 10;
        int b = a;
    }
}

反编译出来的字节码文件:

Main字节码.jpg

结论:

装箱操作:

Integer a = 10;
//实际执行的是Integer a = Integer.valueOf(10);

拆箱操作:

int b = a;
//实际执行的是int b = a.intValue();

其他&扩展

我们先来看一道面试题:

public class Main {
    public static void main(String[] args) {
        Integer a = 10;
        Integer b = 10;
        Integer c = 128;
        Integer d = 128;
        System.out.println(a == b);
        System.out.println(c == d);
    }
}

内心怀揣自己的真是答案,我们看看下边的源代码:
先看看Integer装箱和拆箱的函数源码:

/**
 * Returns the value of this {@code Integer} as an
 * {@code int}.
 */
public int intValue() {
    return value;
}

/**
 * Returns an {@code Integer} instance representing the specified
 * {@code int} value.  If a new {@code Integer} instance is not
 * required, this method should generally be used in preference to
 * the constructor {@link #Integer(int)}, as this method is likely
 * to yield significantly better space and time performance by
 * caching frequently requested values.
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
  • 拆箱操作:直接返回Integer内的数值
  • 装箱操作:在i大于IntegerCache.low或者i小于IntegerCache.high时返回缓存的Integer对象,否则创建新的Integer对象。
/**
 * Cache to support the object identity semantics of autoboxing for values between
 * -128 and 127 (inclusive) as required by JLS.
 *
 * The cache is initialized on first usage.  The size of the cache
 * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
 * During VM initialization, java.lang.Integer.IntegerCache.high property
 * may be set and saved in the private system properties in the
 * sun.misc.VM class.
 */
private static class IntegerCache {
    /*********/
}

通过源码码我们可以发现,Integer在数据为[-128,127]之间时。使用了IntegerCache 返回缓存中对象的引用,否则new一个新的对象。

看到上面这个答案,有些同学就会想到:除过Integer之前还有其他的基础数据类型,那么其他的类型是否也是专业那个的呢?答案:是也不是。原理想想大家也都明白:

  • Boolean内部有true&false两个静态变量,最后装箱得到的值都是这两个静态变量的引用。
  • Long&Integer&Short&Byte在数值为[-128,127]之间都有Cache。
  • Double&Float则都没有。

所以上面问题的正确答案分别是:true、false。

见识了”==”比较,现在看equals比较结果:
同样我们也先看一道题目:

public class Main {
    public static void main(String[] args) {
        Integer a = 1;
        Integer b = 2;
        Long c = 3L;
        System.out.println(c == (a + b));
        System.out.println(c.equals(a + b));
    }
}

然后我们再看看源码:

/**
 * Compares this object to the specified object.  The result is
 * {@code true} if and only if the argument is not
 * {@code null} and is an {@code Integer} object that
 * contains the same {@code int} value as this object.
 *
 * @param   obj   the object to compare with.
 * @return  {@code true} if the objects are the same;
 *          {@code false} otherwise.
 */
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

在Java中我们知道操作”==”的两个数都是数据包装类型对象的引用的话,那么则是用来比较两个引用所指向的对象是不是同一个;而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。为什么呢,因为”==”两边引用数据类型必须一致,要不然无语错误。

所以我们得到上边题目的答案是:true、false。
因为第一次比较实际是先对数据进行拆箱然后比较,所以得到的结果是true;第二次比较实际是先拆箱(两个Integer对象拆箱)后装箱(将拆箱且计算后的数据再装箱),然后同Long对象比较,显然不是同一类型所以得到false。

以上问题及答案都是作者亲自敲出来的,想实际操作同学也可以反编译class文件看看【真相】。

想阅读作者的更多文章,可以查看我的公共号:

振兴书城

查看评论

自动装箱和自动拆箱(AutoBoxing,Unboxing)

什么是自动装箱拆箱 基本数据类型的自动装箱(autoboxing)、拆箱(unboxing)是自J2SE 5.0开始提供的功能。  一般我们要创建一个类的对象实例的时候,我们会这样:  Cla...
  • u013078669
  • u013078669
  • 2016-10-09 13:38:13
  • 2342

跟着小白浅谈"自动装箱及自动拆箱"

自动装箱及自动拆箱篇:     今天小白和大家们谈谈什么是自动装箱及自动拆箱,那么什么是自动装箱和拆箱了? 其实就是包装类(wrapper)提供的一种机制自动装箱(autoboxing)自动拆箱(u...
  • qq1723205668
  • qq1723205668
  • 2016-06-05 13:50:59
  • 1186

Java 自动装箱和自动拆箱注意的问题

自动装箱和自动拆箱不是什么复杂的技术,自动装箱就是基本类型(int,long)数据可以先自动转换为对应的封装类(Integer,Long)对象,而自动拆箱相反。 在本文中,笔者向大家介绍下Java中...
  • chenchaofuck1
  • chenchaofuck1
  • 2016-06-15 17:00:48
  • 2535

Java自动装箱和自动拆箱

Java自动装箱和拆箱
  • liamao16
  • liamao16
  • 2016-04-27 08:59:58
  • 1068

Java进阶之自动拆箱与自动装箱

自动装箱:把基本类型用它们对应的包装类包装起来,使它们具有对象的特质,可以调用所对应的包装类所定义的方法,比如toString()等。 自动拆箱:跟自动装箱的方向相反,将Integer及Double...
  • qq_31655965
  • qq_31655965
  • 2016-06-06 18:04:26
  • 2876

【Java】Java的==和equals()以及自动装箱拆箱

Java的==和equals()以及自动装箱拆箱Java的和equals以及自动装箱拆箱 抛一个问题 先说一说 和 equals方法equals方法 再说一下Integer的缓存机制 自动装箱和自动...
  • cflys
  • cflys
  • 2017-07-22 11:02:25
  • 1054

java中的自动拆箱、装箱是指什么?

JAVA语言中有个名词叫自动拆箱、装箱,那这个自动拆箱、装箱到底是指啥?自动拆箱、装箱是从JDK1.5开始才有的特性,其实它主要就是指基本类型与包装类的自动转换。如int 与Integer类型。 i...
  • ckinghan58
  • ckinghan58
  • 2017-05-08 10:51:52
  • 934

关于自动装箱 与自动 和自动拆箱。Integer,Boolean等

其实在jdk5.0 之前,没有自动装箱与自动拆箱的概念。 在那之前都是      Integer a=new Integer(5);         int c=a.intValue(); 通...
  • qq_23476319
  • qq_23476319
  • 2016-12-06 14:16:56
  • 379

自动拆箱&自动装箱以及String 和基本数据类型封装类生成的对象是否相等

自动拆箱(unboxing)&自动装箱(boxing) @author 李东秀|| qq:1028659927 本文主要为自己理解所做的学习笔记,如有不对的地方, 望各位看官不吝指出,代...
  • u010126792
  • u010126792
  • 2017-03-12 13:14:53
  • 788
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 30万+
    积分: 4198
    排名: 9100
    博客专栏
    最新评论