自动装箱的陷阱

深入理解jvm虚拟机第316页关于自动装箱的陷阱:

   Integer a = 1;
        Integer b = 2;
        Integer c = 3;
        Integer d = 3;
        Integer e = 321;
        Integer f = 321;
        Long g = 3L;

        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));//true
        System.out.println(g.equals(a + b));//false

简单一点说,装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。
声明阶段使用自动装箱,将基本数据类型int自动转换为包装类型Integer,但是基本数据类型能表示的范围是-128~127之间。
 1)对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
    如果作用于引用类型的变量,则比较的是所指向的对象的地址
 2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量
如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
    诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。

  public com.yy.dto.TT();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1
       1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;自动装箱,调用的是Integer.valueOf(1)方法
       4: astore_1                            //将栈顶引用型数据存入局部变量
       5: iconst_2
       6: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;自动装箱,调用的是Integer.valueOf(2)方法
       9: astore_2
      10: iconst_3
      11: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;自动装箱,调用的是Integer.valueOf(3)方法
      14: astore_3
      15: iconst_3
      16: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;自动装箱,调用的是Integer.valueOf(3)方法
      19: astore        4
      21: sipush        321                 //将一个短整型常量推入栈顶
      24: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      27: astore        5
      29: sipush        321
      32: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      35: astore        6
      37: ldc2_w        #3                  // long 3l    将long或double型常量值从常量池中推送至栈顶(宽索引)
      40: invokestatic  #5                  // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;自动装箱,3L转换为Long类型
      43: astore        7
      45: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;  输出流
      48: aload_3
      49: aload         4
      51: if_acmpne     58             //比较栈顶两引用型数值,当结果不相等时跳转,这里比较c和d,即指向同一地址。
      54: iconst_1
      55: goto          59
      58: iconst_0
      59: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
      62: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      65: aload         5
      67: aload         6
      69: if_acmpne     76               // 这里比较e和f,由于e和f是两个对象,地址不是同一个,所以为false
      72: iconst_1
      73: goto          77
      76: iconst_0
      77: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
      80: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
      83: aload_3
      84: invokevirtual #8                  // Method java/lang/Integer.intValue:()I 拆箱 c由Integer转为int的3
      87: aload_1
      88: invokevirtual #8                  // Method java/lang/Integer.intValue:()I 把Integer1转为int 1
      91: aload_2
      92: invokevirtual #8                  // Method java/lang/Integer.intValue:()I 把Integer2转为2
      95: iadd                                    // int型的1和2进行相加操作,基本数据类型使用==则比较数值,即3 = 1+2
      96: if_icmpne     103
      99: iconst_1
     100: goto          104
     103: iconst_0
     104: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
     107: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
     110: aload_3
     111: aload_1
     112: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     115: aload_2
     116: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     119: iadd
     120: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 
     123: invokevirtual #9                  // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z 调用的Integer的equals方法,比较数值是否相等。看文末Integer的equals方法源码。
     126: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
     129: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
     132: aload         7
     134: invokevirtual #10                 // Method java/lang/Long.longValue:()J将Long类型转换为long类型
     137: aload_1
     138: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     141: aload_2
     142: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     145: iadd
     146: i2l
     147: lcmp
     148: ifne          155
     151: iconst_1
     152: goto          156
     155: iconst_0
     156: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
     159: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
     162: aload         7
     164: aload_1
     165: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     168: aload_2
     169: invokevirtual #8                  // Method java/lang/Integer.intValue:()I
     172: iadd
     173: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     176: invokevirtual #11                 // Method java/lang/Long.equals:(Ljava/lang/Object;)Z 调用Long类型的equals方法,由于a+b进行运算,需要自动拆箱,然后变为int型1和2求和得3,由于基本数据类型不能用于equals方法,自动装箱为Integer类型的3,而Long类型的equals方法,比较的若不是Long类型,直接返回false。
     179: invokevirtual #7                  // Method java/io/PrintStream.println:(Z)V
     182: return
}

Integer的equals方法源码:

 public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

该方法中将Integer类型的obj转换为int型,然后使用 == ,即比较两个基本数据类型的数值是否相等。

Long类型的equals的方法源码如下:

 public boolean equals(Object obj) {
        if (obj instanceof Long) {
            return value == ((Long)obj).longValue();
        }
        return false;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值