今天使用findbugs掃描項目后發現很多高危漏洞,其中非常常見的一個是比較兩個Long或Integer時直接使用的==來比較。 其實這樣是錯誤的。
因為Long與Ineger都是包裝類型,是對象。 而不是普通類型long與int , 所以它們在比較時必須都應該用equals,或者先使用longValue()或intValue()方法來得到他們的基本類型的值然后使用==比較也是可以的。
但是有一種特殊情況, 其實Long與Integer都將 -128~127 這些對象緩存了。 可以看看Long類型源碼里面有一個LongCache類,代碼如下:
1
2
3
4
5
6
7
8
9
10
|
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 ); } } |
先看看這個例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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)); } } |
打印的結果是:
1
2
|
a == b ? true c == d ? false |
原因
首先來看看 Long a = 5L ; 它是如何將一個基本類型long包裝成一個對象Long的 。
可以寫一個測試類,然后反編譯一下,看看java它是如何解析Long a = 5L這樣一條命令的 。
測試類如下:
1
2
3
|
public class Test06 { Long l = 3L; } |
然后使用javap -verbose Test06 就能看到反編譯的結果了, 下面是輸出的部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
{ 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()方法是如何定義的:
1
2
3
4
5
6
7
|
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方法:
1
2
3
4
5
6
|
public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue(); } return false ; } |
它是先通過.longValue()方法獲取Long對象的基本類型long的值之后再做比較的。
所以對于Integer與Long的比較,最好是使用equals來比較才能確保得到我們想要的結果。
Integer與Long一樣,這里就不舉例了。
以上這篇細數java中Long與Integer比較容易犯的錯誤總結就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。