自动装箱自动拆箱的实现原理

  • Post author:
  • Post category:其他

什么是自动装箱和自动拆箱?

自动装箱就是Java自动将原始值类型转变为对应的对象,如int 自动转变为Integer的过程。
自动拆箱则反之。

Java是怎么实现自动装箱和拆箱的?

测试代码如下:

public class AutoPacking {
    Integer i1= 1;
    int i2=new Integer(2);
}

编译后,进行反汇编,得到代码如下:

public class com.example.demo.code.AutoPacking {
  java.lang.Integer i1;

  int i2;

  public com.example.demo.code.AutoPacking();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_1
       6: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       9: putfield      #3                  // Field i1:Ljava/lang/Integer;
      12: aload_0
      13: new           #4                  // class java/lang/Integer
      16: dup
      17: iconst_2
      18: invokespecial #5                  // Method java/lang/Integer."<init>":(I)V
      21: invokevirtual #6                  // Method java/lang/Integer.intValue:()I
      24: putfield      #7                  // Field i2:I
      27: return
}

可以看到自动装箱其实是在编译的时候调用了Integer.valueOf()方法,自动拆箱调用的是Integer.intValue()方法。

下面我们来看下valueOf方法:

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

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;
    }
    private IntegerCache() {}
}

通过源码可以看出,Integer 有个有个静态内部类,在编译时生成了一个常量数组Integer cache[],包含-128到127的数据作为缓存。在此期间的数据通过valueOf方法将会返回cache[]中的缓存。

8种基本类型自动装箱都一样吗?

我们看代码:

    //boolean原生类型自动装箱成Boolean
    public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }

    //byte原生类型自动装箱成Byte
    public static Byte valueOf(byte b) {
        final int offset = 128;
        return ByteCache.cache[(int)b + offset];
    }

    //byte原生类型自动装箱成Byte
    public static Short valueOf(short s) {
        final int offset = 128;
        int sAsInt = s;
        if (sAsInt >= -128 && sAsInt <= 127) { // must cache
            return ShortCache.cache[sAsInt + offset];
        }
        return new Short(s);
    }

    //char原生类型自动装箱成Character
    public static Character valueOf(char c) {
        if (c <= 127) { // must cache
            return CharacterCache.cache[(int)c];
        }
        return new Character(c);
    }
    
    //int原生类型自动装箱成Integer
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

    //int原生类型自动装箱成Long
    public static Long valueOf(long l) {
        final int offset = 128;
        if (l >= -128 && l <= 127) { // will cache
            return LongCache.cache[(int)l + offset];
        }
        return new Long(l);
    }

    //double原生类型自动装箱成Double
    public static Double valueOf(double d) {
        return new Double(d);
    }

    //float原生类型自动装箱成Float
    public static Float valueOf(float f) {
        return new Float(f);
    }

我们看到,double 和float两种基本类型,并没有实现常量池,在自动装箱时总是返回新对象。

做几道题试试理解程度?


public class Test {  
   public static void main(String[] args) {      
       test();  
   }  

   public static void test() {  
       int i = 40;  
       int i0 = 40;  
       Integer i1 = 40;  
       Integer i2 = 40;  
       Integer i3 = 0;  
       Integer i4 = new Integer(40);  
       Integer i5 = new Integer(40);  
       Integer i6 = new Integer(0);  
       Double d1=1.0;  
       Double d2=1.0;  
         
       System.out.println("i=i0\t" + (i == i0));  
       System.out.println("i1=i2\t" + (i1 == i2));  
       System.out.println("i1=i2+i3\t" + (i1 == i2 + i3));  
       System.out.println("i4=i5\t" + (i4 == i5));  
       System.out.println("i4=i5+i6\t" + (i4 == i5 + i6));      
       System.out.println("d1=d2\t" + (d1==d2));   
         
       System.out.println();          
   }  
} 

答案是:

i=i0        true
i1=i2       true
i1=i2+i3    true
i4=i5       false
i4=i5+i6    true
d1=d2     false

你答对了吗?


版权声明:本文为zhangzhen02原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。