论坛首页 Java企业应用论坛

自动装箱拆箱原理分析

浏览 2797 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (1) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-03-06  

JDK5.0之后为程序员提供了一种新特性:自动装箱拆箱,貌似是模仿C#的(到现在貌似有接近2年没有搞C#了,哥刚出来时还是搞C#滴)。

在JDK5.0之前
Integer val = 100;
如果这样写,是错误的(类型转换错误)。


虽然自动装箱拆箱用起来是很简单滴,但是明白它的原理,就能达到知其然,知其所以然的效果。

进入主题,分析自动装箱拆箱的背后原理。

public class Test
{

   public static void main(String[] args) throws Exception
   {

      Integer one = 100;
      Integer two = 100;
    
      Integer three = 200;
      Integer four = 200;
    
      int five = 100;
    
      System.out.println(one == two);
      System.out.println(five == two);
      System.out.println(three == four);
    
   }
}

结果是神马呢?

先不说结果,等分析就自然知道它的结果了。呵呵

先来看看它的字节码,看看它都做了些什么。
public static void main(java.lang.String[])   throws java.lang.Exception;
  Exceptions:
   throws java.lang.Exception  Code:
   Stack=3, Locals=6, Args_size=1
   0:   bipush  100    // 将常数100压栈
   2:   invokestatic    #19; //Method java/lang/Integer.valueOf:(I)Ljava/lang/I
teger; // 调用Integer的valueOf方法
   5:   astore_1 // 将100赋给第一个变量
   6:   bipush  100 // 将常数100压栈
   8:   invokestatic    #19; //Method java/lang/Integer.valueOf:(I)Ljava/lang/I
teger; // 调用Integer的valueOf方法
   11:  astore_2 // 将100赋给第一个变量
   12:  sipush  200
   15:  invokestatic    #19; //Method java/lang/Integer.valueOf:(I)Ljava/lang/I
teger;
   18:  astore_3
   19:  sipush  200
   22:  invokestatic    #19; //Method java/lang/Integer.valueOf:(I)Ljava/lang/I
teger;
   25:  astore  4
   27:  bipush  100
   29:  istore  5
   31:  getstatic       #25; //Field java/lang/System.out:Ljava/io/PrintStream;
   34:  aload_1
   35:  aload_2
   36:  if_acmpne       43
   39:  iconst_1
   40:  goto    44
   43:  iconst_0
   44:  invokevirtual   #31; //Method java/io/PrintStream.println:(Z)V
   47:  getstatic       #25; //Field java/lang/System.out:Ljava/io/PrintStream;
   50:  iload   5
   52:  aload_2
   53:  invokevirtual   #37; //Method java/lang/Integer.intValue:()I // 调用Integer的intValue方法
   56:  if_icmpne       63
   59:  iconst_1
   60:  goto    64
   63:  iconst_0
   64:  invokevirtual   #31; //Method java/io/PrintStream.println:(Z)V
   67:  getstatic       #25; //Field java/lang/System.out:Ljava/io/PrintStream;
   70:  aload_3
   71:  aload   4
   73:  if_acmpne       80
   76:  iconst_1
   77:  goto    81
   80:  iconst_0
   81:  invokevirtual   #31; //Method java/io/PrintStream.println:(Z)V
   84:  return


看了字节码后,有点恍然大悟的感觉。

1、装箱
原来执行下面语句时
Integer one = 100;

调用了Integer的静态方法valueOf(这可能是编译器处理的)。
public static Integer valueOf(int i) {
   final int offset = 128;
   if (i >= -128 && i <= 127) { // must cache
       return IntegerCache.cache[i + offset];
   }
    return new Integer(i);
}

此方法是JDK5.0之后才提供的,也就是所谓的“装箱”操作了。如果i的值在-128到127这个范围内,就会从“缓存”里面取它的值,如果超过这个范围的数,就直接返回i所代表的包装类。对-128到127这个范围内的数字进行缓存,可能是出于效率的考虑吧。

private static class IntegerCache {
   private IntegerCache(){}

   static final Integer cache[] = new Integer[-(-128) + 127 + 1];

   static {
       for(int i = 0; i < cache.length; i++)
      cache[i] = new Integer(i - 128);
   }
}


2、拆箱
System.out.println(five == two);

执行这句的时候,会把two转成原始int类型。调用Integer的实例方法intValue。
public int intValue() {
   return value;
}

其中value是Integer的一个成员变量,
private final int value;

简单吧,哈哈。。。。现在答案已经出来了。
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics