Summarize the mistakes that Long and Integer are more likely to make in java

  • 2020-06-01 09:50:56
  • OfStack

Today, many high-risk vulnerabilities have been found using the findbugs scanning program. One of the most common is the direct == used when comparing two Long or Integer. This is wrong.

Because Long and Ineger are both wrapper types, they are objects. Instead of the normal types long and int, they must all be compared using equals, or you can use the longValue() or intValue() methods to get the values of their basic types first and then compare them using ==.

However, there is a special case in which both Long and Integer cache -128~127 objects. You can look at the Long source code has a class LongCache, the code is as follows:


private static class LongCache {
 private LongCache(){}

 static final Long cache[] = new Long[-(-128) + 127 + 1];

 static {
   for(int i = 0; i < cache.length; i++)
 cache[i] = new Long(i - 128);
 }
  }

Here's an example:


public class Test05 {

  public static void main(String[] args) {
    Long a = 5L;
    Long b = 5L;

    System.out.println("a == b ? " + (a == b));

    Long c = 129L;
    Long d = 129L;
    System.out.println("c == d ? " + (c == d));
  }
}

The result is:


a == b ? true
c == d ? false


why

First let's look at Long a = 5L; How it wraps a base type long into an object Long.

You can write a test class, decompile 1, and see how java parses a command like Long a = 5L.

The test classes are as follows:


public class Test06 {
  Long l = 3L;
}

You can then use javap-verbose Test06 to see the decompile results. Here is the output:


{
java.lang.Long l;

public com.spring.test.Test06();
 Code:
  Stack=3, Locals=1, Args_size=1
  0:  aload_0
  1:  invokespecial  #10; //Method java/lang/Object."<init>":()V
  4:  aload_0
  5:  ldc2_w #12; //long 3l
  8:  invokestatic  #14; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
  11: putfield    #20; //Field l:Ljava/lang/Long;
  14: return
 LineNumberTable:
  line 3: 0
  line 5: 4
  line 3: 14

 LocalVariableTable:
  Start Length Slot Name  Signature
  0   15   0  this    Lcom/spring/test/Test06;


}

It can be seen from the 8 in Code that one class method Long.valueOf (Long) of Long is called, so it can be concluded that Long a = 5L is actually equal to Long a = Long.valueOf (5);

Then look at how the Long.valueOf () method is defined:


 public static Long valueOf(long l) {
 final int offset = 128;
 if (l >= -128 && l <= 127) { // will cache
   return LongCache.cache[(int)l + offset];
 }
    return new Long(l);
  }

If the value of the basic type is between -128 and 127, the cached object will be retrieved directly from LongCache, otherwise, a new new1 Long object will be returned.

Now it is not hard to understand Test05 program execution results, because a b equal to 5, within 127 ~ 128, and so are directly from LongCache return 1 Long object inside, so they are using the = = comparison, is equal to (for object types, the = = comparison are two object reference address of heap), and c and d equals 129, not in - between 127 and 128, So they they are the two new Long objects that come out of new, and the comparison using == is naturally unequal.

Long rewrites the equals method:


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

It is compared after getting the value of long, the base type of Long object, through the.longValue () method.

So for Integer versus Long, it's best to use equals to make sure we get the results we want.

Integer is the same as Long1.


Related articles: