JAVA中Long与Integer比较容易犯的错误

今天使用findbugs扫描项目后发现不少高危漏洞,其中很是常见的一个是比较两个Long或Integer时直接使用的==来比较。 其实这样是错误的。java

由于Long与Ineger都是包装类型,是对象。  而不是普通类型long与int , 因此它们在比较时必须都应该用equals,或者先使用longValue()或intValue()方法来获得他们的基本类型的值而后使用==比较也是能够的。spring

可是有一种特殊状况, 其实Long与Integer都将 -128~127 这些对象缓存了。  能够看看Long类型源码里面有一个LongCache类,代码以下:缓存

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

先看看这个例子:测试

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

打印的结果是:this

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

缘由spa

首先来看看 Long a = 5L ; 它是如何将一个基本类型long包装成一个对象Long的 。code

 能够写一个测试类,而后反编译一下,看看java它是如何解析Long a = 5L这样一条命令的 。orm

测试类以下:对象

public class Test06 {  
    Long l = 3L;  
}

而后使用javap -verbose Test06 就能看到反编译的结果了, 下面是输出的部分:ci

{  
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;  
  
}

从Code中的8能够看出调用了Long的一个类方法Long.valueOf(Long) , 因此能够获得的结论是Long a = 5L实际上等于 Long a = Long.valueOf(5) ;

而后再看看Long.valueOf()方法是如何定义的:

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

一目了然,会先判断基本类型的值若是在-128~127之间,就会直接从LongCache里面取出缓存的对象返回,不然就new一个新的Long对象返回 。


如今就不难理解Test05程序执行获得的结果了,由于a与b等于5,在-127~128以内,因此都是直接从LongCache里面返回的一个Long对象,因此他们在使用==比较的时候,就是相等的(对于对象类型来讲,==比较的是两个对象的引用指向堆中的地址) ,而c与d等于129,不在-127~128之间,因此他们他们是分别new出来的两个新的Long对象,使用==来比较天然是不相等的了。

Long重写了equals方法:

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

equals方法是先经过.longValue()方法获取Long对象的基本类型long的值以后再作比较的。

因此对于Integer与Long的比较,最好是使用equals来比较才能确保获得咱们想要的结果。

Integer与Long同样,这里就不举例了。

相关文章
相关标签/搜索