看看下面的代码,你真的理解了包装类和自动装箱吗?

废话不多说,上代码

public class Zms{

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

不妨先简单思考一下这六句打印语句的输出是什么?如果能第一时间做出判断,那么OK你已经掌握了;

下面是运行结果:
运行结果
如果你的判断失误了,请跟着我的思路一起来看看具体是为什么?

第一步:查看class文件

我们都知道 Integer 是包装类,在执行Integer a = 1; 语句时系统会进行自动装箱;那么他真正的执行语句是怎么样的呢?下面是编译后的文件:不想看的可以跳过class文件直接看分析

 public <init>()V
   L0
    LINENUMBER 9 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/example/zmsjava/jvmdemo/Zdzx; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x9
  public static main([Ljava/lang/String;)V
    // parameter  args
   L0
    LINENUMBER 12 L0
    ICONST_1
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ASTORE 1
   L1
    LINENUMBER 13 L1
    ICONST_2
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ASTORE 2
   L2
    LINENUMBER 14 L2
    ICONST_3
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ASTORE 3
   L3
    LINENUMBER 15 L3
    ICONST_3
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ASTORE 4
   L4
    LINENUMBER 16 L4
    SIPUSH 321
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ASTORE 5
   L5
    LINENUMBER 17 L5
    SIPUSH 321
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ASTORE 6
   L6
    LINENUMBER 18 L6
    LDC 3
    INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;
    ASTORE 7
   L7
    LINENUMBER 19 L7
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 3
    ALOAD 4
    IF_ACMPNE L8
    ICONST_1
    GOTO L9
   L8
   FRAME FULL [[Ljava/lang/String; java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Long] [java/io/PrintStream]
    ICONST_0
   L9
   FRAME FULL [[Ljava/lang/String; java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Long] [java/io/PrintStream I]
    INVOKEVIRTUAL java/io/PrintStream.println (Z)V
   L10
    LINENUMBER 20 L10
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 5
    ALOAD 6
    IF_ACMPNE L11
    ICONST_1
    GOTO L12
   L11
   FRAME SAME1 java/io/PrintStream
    ICONST_0
   L12
   FRAME FULL [[Ljava/lang/String; java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Long] [java/io/PrintStream I]
    INVOKEVIRTUAL java/io/PrintStream.println (Z)V
   L13
    LINENUMBER 21 L13
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 3
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    ALOAD 1
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    ALOAD 2
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    IADD
    IF_ICMPNE L14
    ICONST_1
    GOTO L15
   L14
   FRAME SAME1 java/io/PrintStream
    ICONST_0
   L15
   FRAME FULL [[Ljava/lang/String; java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Long] [java/io/PrintStream I]
    INVOKEVIRTUAL java/io/PrintStream.println (Z)V
   L16
    LINENUMBER 22 L16
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 3
    ALOAD 1
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    ALOAD 2
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    IADD
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    INVOKEVIRTUAL java/lang/Integer.equals (Ljava/lang/Object;)Z
    INVOKEVIRTUAL java/io/PrintStream.println (Z)V
   L17
    LINENUMBER 23 L17
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 7
    INVOKEVIRTUAL java/lang/Long.longValue ()J
    ALOAD 1
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    ALOAD 2
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    IADD
    I2L
    LCMP
    IFNE L18
    ICONST_1
    GOTO L19
   L18
   FRAME SAME1 java/io/PrintStream
    ICONST_0
   L19
   FRAME FULL [[Ljava/lang/String; java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Integer java/lang/Long] [java/io/PrintStream I]
    INVOKEVIRTUAL java/io/PrintStream.println (Z)V
   L20
    LINENUMBER 24 L20
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 7
    ALOAD 1
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    ALOAD 2
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    IADD
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    INVOKEVIRTUAL java/lang/Long.equals (Ljava/lang/Object;)Z
    INVOKEVIRTUAL java/io/PrintStream.println (Z)V
   L21
    LINENUMBER 27 L21
    RETURN
   L22
    LOCALVARIABLE args [Ljava/lang/String; L0 L22 0
    LOCALVARIABLE a Ljava/lang/Integer; L1 L22 1
    LOCALVARIABLE b Ljava/lang/Integer; L2 L22 2
    LOCALVARIABLE c Ljava/lang/Integer; L3 L22 3
    LOCALVARIABLE d Ljava/lang/Integer; L4 L22 4
    LOCALVARIABLE e Ljava/lang/Integer; L5 L22 5
    LOCALVARIABLE f Ljava/lang/Integer; L6 L22 6
    LOCALVARIABLE g Ljava/lang/Long; L7 L22 7
    MAXSTACK = 5
    MAXLOCALS = 8
}

可以看到自动装箱是用到了Integer.valueOf() 这个方法。
看看下面的代码,你真的理解了包装类和自动装箱吗?_第1张图片

第二步:查看Integer.valueOf()方法

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

结合下面代码一起来看
看看下面的代码,你真的理解了包装类和自动装箱吗?_第2张图片
可以得出结论:
在[-128,127]之间的时候他会直接拿缓存,而不会new Integer(),Integer.valueOf()方法基于减少对象创建次数和节省内存的考虑,缓存了[-128,127]之间的数字。此数字范围内传参则直接返回缓存中的对象。在此之外,直接new出来。
这样就解释了第二个输出为什么是false,因为他超出范围,每次都是new对象,引用并不一致。
但是这样并不能解决第五和第六行为什么分别为 true 和false

查看 equals 方法

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

可以看到equals方法需要类型和内容都相同才会返回true;而根据class文件可以看出这里的类型是不相同的。

当一个基础数据类型与封装类进行==、+、-、*、/运算时,会将封装类进行拆箱,对基础数据类型进行运算。所以System.out.println(g == (a + b)); 最终执行语句为 System.out.println(g == (long)(a + b)); ,第五行为true也就解释了。

参考:https://www.cnblogs.com/wang-yaz/p/8516151.html

你可能感兴趣的:(java,jvm,深入理解JAVA虚拟机,java,jvm,jdk)