对于java1.5引入的自动装箱拆箱,之前只是知道一点点,最近在看一篇博客时发现自己对自动装箱拆箱这个特性了解的太少了,所以今天研究了下这个特性。以下是结合测试代码进行的总结。

测试代码:

        int a = 1;
        Integer b = 1;
        Integer c = 1;
        Integer d = 2;
        Integer e = 3;
        Integer f = 128;
        Integer g = 128;
        Long h = 3L;
        Double m = 4.0;
        Double n = 4.0;
        Float p = 5f;
        Float q = 5f;
        System.out.println("a == b : " + (a == b));  //true
        System.out.println("b ==c : " + (b == c));  //true
        System.out.println("e == (c + d) : " + (e == (c + d)));  //true
        System.out.println("e.equals(c + d) : " + (e.equals(c + d)));  //true
        System.out.println("h == (c + d) : " + (h == (c + d))); //true
        System.out.println("h.equals(c + d) : " + (h.equals(c + d)));  //false
        System.out.println("f == g : " + (f == g)); //false
        System.out.println("m == n : " + (m == n)); //false
        System.out.println("p == q : " + (p == q)); //false
        System.out.println("m == d * 2 : " + (m == d * 2)); //true
        System.out.println("p == (d + e) : " + (p == (d + e))); //true

测试输出结果与说明:


 1. a == b : true
     当基本类型包装类与基本类型值进行==运算时,包装类会自动拆箱。即比较的是基本类型值。
     具体实现上,是调用了Integer.intValue()方法实现拆箱。
     可以在测试代码处打断点,使用F5快捷键step
    into至每一步执行方法,会看到调用了Integer.intValue()方法实现了拆箱。
 2. b == c : true
    b和c类型均为Integer包装类,故对基本类型进行自动装箱后赋值给b和c。
    在进行==运算时不会触发拆箱操作。所以比较的是引用地址,说明b和c是同一个对象。
    java中自动装箱调用的是Integer.valueOf()方法实现的,可以像例1一样打断点验证。
    为什么b和c 会是同一个对象呢?查看Integer.valueOf()方法实现即可知道,如下:
    下面的代码中可以看到,对于-128至127这256个值,直接获取的IntegerCache中的值。
    而IntegerCache是Integer中的一个静态内部类,
    里面将-128至127(即一个字节所能表示的所有带符号值 -2^7至2^7-1)的包装类存在了一个数组中。
    对于-128到127之间的数,直接从数组中获取,其他的数则使用new生成。所以此处输出true。

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

    private static class IntegerCache {
        static final int high;
        static final Integer cache[];

        static {
            final int low = -128;

            // high value may be configured by property
            int h = 127;
            if (integerCacheHighPropValue != null) {
                // Use Long.decode here to avoid invoking methods that
                // require Integer's autoboxing cache to be initialized
                int i = Long.decode(integerCacheHighPropValue).intValue();
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - -low);
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);
        }

 3. e == (c + d) : true
    包装类在执行加减乘除求余等运算时,会触发拆箱操作,故c、d拆箱后相加,
    结果为基本类型;然后e与基本类型进行==运算,触发拆箱操作。
 4. e.equals(c + d) : true
    首先,c + d 拆箱运算得到基本类型值;然后当进行equals运算时,
    会触发基本类型值的装箱操作,c + d 的结果会自动装箱为包装类;最后与e进行equals运算。
 5. h == (c + d) : true
    运算顺序与上面例3中一致,唯一区别是h自动拆箱是调用了Long.longValue()实现。
 6. h.equals(c + d) : false
    运算顺序与上面例4中一致,为false的原因在于c + d的运算结果自动装箱后类型为Integer,
    而h的类型为Long,类型不一样,equals的结果为false。
 7. f == g : false
     请参考上面例2中的解释。
     超出了-128至127的缓存范围,故在valueOf()方法中使用new生成了新对象。

 8. m == n : false
    p == q : false
    与上面例子1、2中的结果不同,对于Boolean、Byte、Character、Short、Integer、Long六种基本类型,
    对于一个字节以内的值-128到127(Boolean只有true和false)都实现了缓存机制。
    不在此范围的数才在对应的valueOf()方法中new出一个新的对象。
    但是对于Double和Float类型的浮点数据,在-128到127之间除了256个整数外还有无数的小数,
    故java中没有实现Double和Float中一些数的缓存。
    所以,对于Double和Float的自动装箱,都是new出新的对象。故此两例均输出false。

 10. m == d * 2 : true
     p == (d + e) : true
     请参考例3和例5。

反编译后代码:

使用java反编译工具,对class字节码文件进行反编译,结果如下所示。从下面的反编译代码,我们可以看到java是如何实现自动装箱、拆箱的。

    int a = 1;
    Integer b = Integer.valueOf(1);
    Integer c = Integer.valueOf(1);
    Integer d = Integer.valueOf(2);
    Integer e = Integer.valueOf(3);
    Integer f = Integer.valueOf(128);
    Integer g = Integer.valueOf(128);
    Long h = Long.valueOf(3L);
    Double m = Double.valueOf(4.0D);
    Double n = Double.valueOf(4.0D);
    Float p = Float.valueOf(5.0F);
    Float q = Float.valueOf(5.0F);
    System.out.println("a == b : " + (a == b.intValue()));
    System.out.println("b ==c : " + (b == c));
    System.out.println("e == (c + d) : " + (e.intValue() == c.intValue() + d.intValue()));
    System.out.println("e.equals(c + d) : " + e.equals(Integer.valueOf(c.intValue() + d.intValue())));
    System.out.println("h == (c + d) : " + (h.longValue() == c.intValue() + d.intValue()));
    System.out.println("h.equals(c + d) : " + h.equals(Integer.valueOf(c.intValue() + d.intValue())));
    System.out.println("f == g : " + (f == g));
    System.out.println("m == n : " + (m == n));
    System.out.println("p == q : " + (p == q));
    System.out.println("m == d * 2 : " + (m.doubleValue() == d.intValue() * 2));
    System.out.println("p == (d + e) : " + (p.floatValue() == d.intValue() + e.intValue()));

参考文章:

①Java 自动装箱和拆箱

②Java自动装箱与拆箱及其陷阱

③深入剖析Java中的装箱和拆箱

④四道Java基础题 你能对几道?

java自动装箱拆箱总结的更多相关文章

  1. JAVA自动装箱拆箱与常量池

    java 自动装箱与拆箱 这个是jdk1.5以后才引入的新的内容,作为秉承发表是最好的记忆,毅然决定还是用一篇博客来代替我的记忆: java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的 ...

  2. Java 自动装箱/拆箱

    自动装箱/拆箱大大方便了基本类型(8个基本类型)数据和它们包装类的使用 自动装箱 : 基本类型自动转为包装类(int >> Integer) 自动拆箱: 包装类自动转为基本类型(Integ ...

  3. Java自动装箱拆箱

    一.装箱.拆箱定义 如果一个int型量被传递到需要一个Integer对象的地方,那么,编译器将在幕后插入一个对Integer构造方法的调用,这就叫做自动装箱.而如果一个Integer对象被放到需要in ...

  4. 深入理解Java自动装箱拆箱机制

    1.自动装箱与拆箱的定义 装箱就是自动将基本数据类型转换为包装器类型(int-->Integer): 拆箱就是自动将包装器类型转换为基本数据类型(Integer-->int). Java中 ...

  5. 那些年一起踩过的坑 — java 自动装箱拆箱问题

    坑在哪里?   我们都知道Java的八种基本数据类型:int, short, long, double, byte, char, float, boolean   分别有各自对应的包装类型:Integ ...

  6. Java 的自动装箱拆箱

    Java 是面向对象的语言,其基本数据类型也就有了相对应的类,称为包装类.以下是基本数据类型对应的包装类: 基本数据类型 包装类 byte(1字节) Byte short(2字节) Short int ...

  7. Java八种基本数据类型的大小,以及封装类,自动装箱/拆箱的用法?

    参考:http://blog.csdn.net/mazhimazh/article/details/16799925 1. Java八种基本数据类型的大小,以及封装类,自动装箱/拆箱的用法? 原始类型 ...

  8. java基础1.5版后新特性 自动装箱拆箱 Date SimpleDateFormat Calendar.getInstance()获得一个日历对象 抽象不要生成对象 get set add System.arrayCopy()用于集合等的扩容

    8种基本数据类型的8种包装类 byte Byte short Short int Integer long Long float Float double Double char Character ...

  9. Java的自动装箱/拆箱

    概述 自JDK1.5开始, 引入了自动装箱/拆箱这一语法糖, 它使程序员的代码变得更加简洁, 不再需要进行显式转换.基本类型与包装类型在某些操作符的作用下, 包装类型调用valueOf()方法将原始类 ...

随机推荐

  1. SocketServer源码学习(一)

    SocketServer其实是对socket更高级的封装正如官网上说的:The socketserver module simplifies the task of writing network s ...

  2. [LeetCode] Redundant Connection II 冗余的连接之二

    In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) f ...

  3. [LeetCode] Design Log Storage System 设计日志存储系统

    You are given several logs that each log contains a unique id and timestamp. Timestamp is a string t ...

  4. [Codeforces]813F Bipartite Checking

    往期题目补档.既然被选为了经典题就拿来写一写. Description 给定一张含有n个点的无向图,一开始图中没有任何边.依次给出q次操作,每次操作给出两个点“x y”,若x和y之间没有边相连,则连上 ...

  5. hdu 1402 FFT(模板)

    A * B Problem Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  6. JS文件中获取contextPath的方法

    function getContextPath() {    var pathName = document.location.pathname;    var index = pathName.su ...

  7. 数据结构之堆Heap

    1. 概述 堆(也叫优先队列),是一棵完全二叉树,它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆).它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等. 2. 堆 ...

  8. Vim8.0在Debian下,normal模式的O命令出现延时

    Update 2018/4/26 问题是什么 在Debian的Vim8.0中,normal模式下,使用O创建新行,常常出现延迟情况:按下O后,可以看见O首先在当前光标位置出现,过了大约0.5-1秒,接 ...

  9. C# 获取当前屏幕DPI

    1.通过Graphics类获取 Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(mainWindow).Han ...

  10. 我在 Ubuntu 下使用 Sublime 编写 python 代码时遇到并解决的问题

    Ubuntu 下 Sublime 无法输入中文 解决方法如下: sudo apt-get update && sudo apt-get upgrade 克隆项目到本地 : git cl ...