I. Problem description

The following problems were encountered during development

Long a = 100L;
Long b = 100L;
System.out.println(a == b);
System.out.println(a.equals(b));
System.out.println(a == 100);
System.out.println(a.equals(100));Copy the code

Output result:

true
true
true
falseCopy the code

But when Long is greater than 127:

Long a = 128L;
Long b = 128L;
System.out.println(a == b);
System.out.println(a.equals(b));
System.out.println(a == 128);
System.out.println(a.equals(128));Copy the code

Output result:

false
true
true
falseCopy the code

 

Ii. Problem analysis

View the source code: java.lang.long.java

LongCache pre-caches numbers in the range -128 — 127 for better space and time performance by caching frequently requested values.

When the data is outside the range, a new Long object is created;

“==” is the address of the comparison. Data addresses outside this range are inconsistent, so the comparison within the range is true, and the comparison outside the range is false.

A ==100 automatically converts int to Long for comparison, so it prints true;

In long.java we overwrite equals() to compare types first and values first, so a.equals(100) prints false;

 

Three, source code analysis (disassembly)

Let’s take a look at the following example code and consider the output:

public class IntTest { public static void main(String[] args) { Integer a = 100, b = 100, c = 150, d = 150; System.out.println(a == b); System.out.println(c == d); }}Copy the code

You can get the answer by running the code, and the program outputs the results: true, false.

First compile the source code: javac IntTest. Java

You then need to disassemble the code by executing: Javap -c IntTest

After decompiling, we have the following code:

Compiled from "IntTest.java"
public class com.chujianyun.common.int_test.IntTest {
  public com.chujianyun.common.int_test.IntTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: bipush        100
       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       5: astore_1
       6: bipush        100
       8: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      11: astore_2
      12: sipush        150
      15: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      18: astore_3
      19: sipush        150
      22: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      25: astore        4
      27: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      30: aload_1
      31: aload_2
      32: if_acmpne     39
      35: iconst_1
      36: goto          40
      39: iconst_0
      40: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
      43: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      46: aload_3
      47: aload         4
      49: if_acmpne     56
      52: iconst_1
      53: goto          57
      56: iconst_0
      57: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V
      60: return
}Copy the code

You can explicitly “see” these four integers var =? Formally declared variables do construct Integer ‘objects using java.lang.Integer#valueOf(int).

Next, the compiled code is analyzed in detail. If you do not understand it, you can skip it: according to Java Virtual Machine Specification: Java SE 8 Edition 3, later abbreviated as JVMS, chapter 6, a description of the Virtual machine instruction set, and Appendix B, “Table of Virtual Machine Bytecode Instructions,” pages 4 414-149 of Understanding the Java Virtual Machine. We interpret the above instructions:

  • The instruction offset to 0 is: bipush 100, which means to push the one-byte integer constant 100 to the top of the operand stack;
  • Offset for the 2 orders for: invokestatic # 2 / Method/Java/lang/Integer. The valueOf: (I) Ljava/lang/Integer; Java.lang.Integer#valueOf(int);
  • The instruction with offset 5 is astore_1, which pops the object reference from the operand stack and stores it in the first local variable Slot.
  • The instructions for offsets 6 to 25 are similar;
  • The instruction with offset 30 is ALOAD_1, which means fetching the object reference (that is, a) from the first local variable Slot and pushing it onto the stack;
  • The instruction offset 31 is ALOad_2, which means taking the object reference (that is, B) from the second local variable Slot and pushing it on the stack;
  • The instruction offset to 32 is ifAcmpn, which is the conditional jump instruction, ifThe prefix a indicates the reference comparison of the object.

This instruction has the following features: if_ACmPEq compares values of two reference types on the stack and jumps if they are equal. If_acmpne compares values of two reference types on the stack and jumps if they are not equal

  • Because of caching problems with Integer, a and B references point to the same address, so this condition is not true (if true, it jumps to the instruction with an offset of 39) and executes the instruction with an offset of 35.
  • Instruction with offset 35: iconst_1, which means to push constant 1. (In Java VMS, Boolean operation type is int, where true is represented by 1. For details, see 2.11.1 Data Types and Java VMS.
  • The goto instruction with offset 36 is then executed to jump to the instruction with offset 40.
  • Migration of 40 instructions: invokevirtual # 4 / Java/Method/IO/PrintStream. Println (Z) V.

The parameter descriptor is Z, and the return value descriptor is V.

According to 4.3.2 Field descriptors, the Z character for FieldType indicates a Boolean type and the value is true or false. According to 4.3.3 Field descriptor, the return value is void.

So you can see that the java.io.PrintStream#println(Boolean) function is finally called to print the constant at the top of the stack, which is true.

  • Then compare the execution of instructions between offsets 43 and 57, compare C and D, and print false.
  • Execute the instruction with offset 60, retrun, and the program ends.

We also write an example fragment of type Long:

public class LongTest { public static void main(String[] args) { Long a = -128L, b = -128L, c = 150L, d = 150L; System.out.println(a == b); System.out.println(c == d); }}Copy the code

We get the following decompiled code:

public class com.imooc.basic.learn_int.LongTest {
  public com.imooc.basic.learn_int.LongTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc2_w        #2                  // long -128l
       3: invokestatic  #4                  // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
       6: astore_1
       7: ldc2_w        #2                  // long -128l
      10: invokestatic  #4                  // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
      13: astore_2
      14: ldc2_w        #5                  // long 150l
      17: invokestatic  #4                  // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
      20: astore_3
      21: ldc2_w        #5                  // long 150l
      24: invokestatic  #4                  // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
      27: astore        4
      29: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
      32: aload_1
      33: aload_2
      34: if_acmpne     41
      37: iconst_1
      38: goto          42
      41: iconst_0
      42: invokevirtual #8                  // Method java/io/PrintStream.println:(Z)V
      45: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
      48: aload_3
      49: aload         4
      51: if_acmpne     58
      54: iconst_1
      55: goto          59
      58: iconst_0
      59: invokevirtual #8                  // Method java/io/PrintStream.println:(Z)V
      62: return
}Copy the code

Long var =? It is true that java.lang.Long#valueOf(long) is used to construct objects.

3. Solution to the problem

Do not use “==” for Long comparisons. Try to avoid direct comparisons of Long

Convert Long to base type and compare: a.longValue() == b.longValue(), or 0 == long.pare (a, b);