很多東西,表面上看起來挺簡單,實際上別有洞天,一不小心就是一個坑。記錄一下昨天遇到的Integer數值比較所遇到的“奇葩BUG”。
1.問題場景
先看如下一段代碼
if(activity.getTotalCounts()==activity.getParticipationCounts()) {
long time = activity.getUpdatedAt().getTime()+60*30*1000;
vo.setProbableOpenTime(new Date(time));
}
activity.getTotalCounts() 和activity.getParticipationCounts()的值都是Integer類型,在兩者數值都一樣的時候,測試發現vo.setProbableOpenTime(new Date(time)); 這段代碼竟然有時候能執行到,有時候卻不行。比如 都等於100時,能夠執行到這段代碼,都等於200時卻不行了,好奇怪的問題,都是一樣的數值怎麼就有時候成立,有時候不成立呢!於是有了下面這段測試代碼
2.Integer數值比較單元測試
@Test
public void IntegerTest() {
Integer a = 100;
Integer b = 100;
Integer c = 300;
Integer d = 300;
System.out.println(a==b);
System.out.println(c==d);
System.out.println(c.equals(d));
}
輸出結果爲:
true
false
true
結果可知,Integer 用==比較數值確實有時候成立,有時候卻不行。
3.問題的本質
想知道爲啥有這麼奇怪的結果,還是要看看源代碼的,如下:
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer a = 100實際上調用了valueOf(int i)方法。
這裏low是-128,high是127,從方法的註釋中可以得知,在[-128,127]之間,Integer總是緩存了相應數值對象,這樣每次取值時都是同一個對象,而不在此區間時,則不一定會緩存,那麼取出兩個同樣數值大小的對象則不是同一個對象,每次都會new Integer(i);,所以其對象的地址不同,則用==比較是自然不會成立。Integer緩存的目的正如註釋所言better space and time performance by caching frequently requested values.但是個人以爲這樣的設計又何嘗不是雷區!
爲了防止不小心掉入這樣的陷阱,對於基本類型的比較,用“==”;而對於基本類型的封裝類型和其他對象,應該調用public boolean equals(Object obj)方法(複雜對象需要自己實現equals方法)。
昨天解決完問題,突然靈光一現,我嚓,這是多有趣的一道面試題啊,下次面試別人時,我得問問,哈哈!