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同樣,這裏就不舉例了。

相關文章
相關標籤/搜索