浅谈JAVA 自动装箱与类型转换常有问题

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

Integer box = 321;int basic = box;

作为Java代码中我们最常用到的一类语法糖

我们应当对其做一些“了解”

先上代码,不妨先想一下它们的结果……

public class Demo01 {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;
        System.out.println(c == d);
        System.out.println(Objects.equals(c, d));
        System.out.println(e == f);
        System.out.println(c == (a+b));
        System.out.println(c.equals(a+b));
        System.out.println(g == (a+b));
        System.out.println(g.equals(a+b));
    }

}

答案是:

truetruefalsetruetruetruefalse

作为程序员来讲前五个,在这里就不做深究

重点是第五个与第六个

g == (a+b) // trueg.equals((a+b)) // false

基础好的同志可能已经看出了端倪:类型转换

我们看一下编译出来的Class文件

当然,在这之前为了更方便查看,我们更改下它的源码格式:

boolean b1 = g == (a+b);
System.out.println(b1);

使用IDEA查看这一段代码:

boolean b1 = g == (long)(a + b);
System.out.println(b1);

的确,通过类型转换后,实际上是两个 基础数据类型long 在比较,通过字节码也可以看到他们的操作:

      17: aload_3      18: invokevirtual #6                  // Method java/lang/Long.longValue:()J  21: aload_1      22: invokevirtual #7                  // Method java/lang/Integer.intValue:()I  25: aload_2      26: invokevirtual #7                  // Method java/lang/Integer.intValue:()I  29: iadd      30: i2l      31: lcmp

 

 

 那么第六段代码又是如何得出false的呢?结合包装类Long的源码与Class文件中第六段代码就可以得出结论:

    public boolean equals(Object obj) {if (obj instanceof Long) {return value == ((Long)obj).longValue();
        }return false;
    }
    boolean b2 = g.equals(a + b);
    System.out.println(b2);

前端编译器并没有“想当然”的为我们添加上类型转换,毕竟类型比较是equals()的任务之一!(试想一下你重写equals()的三大步骤???)

我们可以为其手动的添加类型转换:

boolean b2 = g.equals((long)(a+b));

添加前后的字节码:

      // 添加前
    17: aload_3
    18: aload_1      19: invokevirtual #6                  // Method java/lang/Integer.intValue:()I  22: aload_2      23: invokevirtual #6                  // Method java/lang/Integer.intValue:()I  26: iadd      27: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;  30: invokevirtual #7                  // Method java/lang/Long.equals:(Ljava/lang/Object;)Z
      // 添加后  18: aload_1      19: invokevirtual #6                  // Method java/lang/Integer.intValue:()I  22: aload_2      23: invokevirtual #6                  // Method java/lang/Integer.intValue:()I  26: iadd      27: i2l      28: invokestatic  #5                  // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;  31: invokevirtual #7                  // Method java/lang/Long.equals:(Ljava/lang/Object;)Z

在计数器27处新增了 i2l 类型转换

实现了我们“想当然”的结果:

true