废话不多说,上代码
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() 这个方法。
第二步:查看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);
}
结合下面代码一起来看
可以得出结论:
在[-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