美文网首页
java装箱与拆箱的深入理解

java装箱与拆箱的深入理解

作者: zivxia | 来源:发表于2016-09-04 09:52 被阅读517次

    Java有一个类型系统有两个部分组成,包含基本类型(byte、char、int、short、long、float、double、boolean)和引用类型。而基本类型则对应着各自的引用类型,称为装箱的基本类型。而引用类型对应着各自的基本类型,称为拆箱的基本类型。对应的类型为:(Byte、Character、Integer、Short、Long、Float、Double、Boolean)

    下面一具体例子来说明装箱与拆箱

    //java 1.5之前创建一个Integer对象
    Integer i = new Integer(10);
    //java 1.5之后有了装箱的特性,直接用下列方式生成一个Integer对象
    //在这个过程中会将int 类型的10自动装箱成为Integer类型
    Integer i = 10;
    //拆箱 输出的值为20,这个过程中,会先将Integer类型的j自动拆箱为基本类型的10,最后完成运算
    Integer j = new Integer(10);
    int k = 10;
    System.out.print(j+k);
    

    下面来说说基本数据类型与其对应的引用类型的区别:

    1. 基本类型只有值,而装箱基本类型既具有值也具有它们对象的同一性(就是两个装箱的基本类型具有相同的值和不同的同一性(对象不一样))
    2. 基本类型只有功能完备的值,而每个装箱类型不仅具有完备的值还具有所有功能值之外的null。
    3. 基本类型通常比装箱基本类型更节省时间和空间。

    下面来举一个《Effective java中》的一个例子进行分析

    Comparator<Integer> comparator = new Comparator<Integer>()
    {
        public int compareTo(Integer first,Integer second)
        {
            return first > second ? 1:first == second ? 0 : -1;
        }
    
    }
    //这两个Integer实例都表示相同的值42
    Integer a = new Integer(42);
    Integer b = new Integer(42);
    int c = comparator.compareTo(a,b);
    //返回值多少 0 ? 但实际结果却是-1,难道 42 < 42 ?
    

    下面就来解释上面例子的原因:
    首先执行 a>b,两个Integer都自动拆箱为42,不成立,则执行 a==b,乍一看,没什么问题,42==42没问题啊,但实际上这是违反了了装箱的同一性,因为a和b都是引用类型,根据上述两个装箱类型具有相同的值和不同的同一性,只是两个对象的比较,即这两个对象是不同对象,所对应的内存也不一样,a!=b。所有正确答案应该是 -1。

    现在来说说装箱和拆箱是怎么实现的:

    public static void main(String[] args){
      Integer i = 10;
      int j = 10;
      System.out.print("i+j = "+(i+j));
    }
    

    打印结果为:

    Paste_Image.png

    反编译class文件得到:

    Paste_Image.png

    第一行是装箱过程,查看源码实际是调用了Integer.valueOf(int)方法返回一个Integer实例
    第三行进行加法运算的时候是拆箱过程,将Integer实例i拆箱为int型,然后进行加法运算,实际是调用了Integer.intValue()方法返回一个int型数据。

    关于装箱与拆箱大致的都讲的差不多了。下面举几个面试中关于装箱与拆箱会问到的例子:

    public class Main 
    {
       public static void main(String[] args) 
      {
          Integer i1 = 100;
          Integer i2 = 100;
          Integer i3 = 200;
          Integer i4 = 200;
    
          System.out.println(i1==i2); //返回true
          System.out.println(i3==i4); //返回false
     }
    }
    

    下面来解释下这个原因

    //这是装箱的源码
    public static Integer valueOf(int i) {    
         return  i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];}
    
    /** * A cache of instances used by {@link Integer#valueOf(int)} and auto-boxing */
    private static final Integer[] SMALL_VALUES = new Integer[256];
    static {    
             for (int i = -128; i < 128; i++){        
                    SMALL_VALUES[i + 128] = new Integer(i);    
             }
    }
    //当值在[-128,127)之间时,装箱操直接取已经cache好的Integer实例,所以i1==i2,当大于127时,每次都是new出来的Integer,指向不同的对象,所以i3!=i4
    
    public class Main {
        public static void main(String[] args) {
     
            Integer a = 1;
            Integer b = 2;
            Integer c = 3;
            Integer d = 3;
            Integer e = 321;
            Integer f = 321;
            Long g = 3L;
            Long h = 2L;
             
            System.out.println(c==d);  //true
            System.out.println(e==f);   // false
            System.out.println(c==(a+b)); // true
            System.out.println(c.equals(a+b));//true
            System.out.println(g==(a+b));//false
            System.out.println(g.equals(a+b));//false
            System.out.println(g.equals(a+h));//true
        }
    }
    
    
    // Example 1: == comparison pure primitive – no autoboxing
            int i1 = 1;
            int i2 = 1;
            System.out.println("i1==i2 : " + (i1 == i2)); // true
    
            // Example 2: equality operator mixing object and primitive
            Integer num1 = 1; // autoboxing
            int num2 = 1;
            System.out.println("num1 == num2 : " + (num1 == num2)); // true
    
            // Example 3: special case - arises due to autoboxing in Java
            Integer obj1 = 1; // autoboxing will call Integer.valueOf()
            Integer obj2 = 1; // same call to Integer.valueOf() will return same
            // cached Object
    
            System.out.println("obj1 == obj2 : " + (obj1 == obj2)); // true
    
            int obj3 = 3;
            Integer obj4 = 3;
            Integer obj5 = new Integer(3);
    
            System.out.println("obj4 == obj5 :  " + (obj4 == obj5));//false
            System.out.println("obj3 == obj5 :  " + (obj3 == obj5));//true
    
            // Example 4: equality operator - pure object comparison
            Integer one = new Integer(1); // no autoboxing
            Integer anotherOne = new Integer(1);
    
            System.out.println("one == anotherOne : " + (one == anotherOne)); // false
    
    //当 "=="运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。另外,对于包装器类型,equals方法并不会进行类型转换
    

    相关文章

      网友评论

          本文标题:java装箱与拆箱的深入理解

          本文链接:https://www.haomeiwen.com/subject/qoklettx.html