java 移位運算的陷阱

[b]起因:[/b]
源於在java.util.BitSet的源碼中發現這樣一條語句:
1L << bitIndex
當bitIndex爲64時,上面語句的返回值爲1,據此猜測java的移位運算使用的是循環移位規則,內容可以參考上一篇博客 "JDK源碼 - BitSet的實現" [url]http://robblog.iteye.com/admin/blogs/568845[/url]

上面的結論是錯誤的。先說說教科書上說的移位運算:
// 左移: 向左移動,右邊補0
for (int i = 0;i < 8 ;i++)
System.out.print( (1 << i) + " ");
output
1 2 4 8 16 32 64 128

// 右移: 向右移動,如果符號位(int型爲32位)爲0,左邊補0,符號位爲1,左邊補1
// 符號位爲1的右移
for (int i = 0;i < 8 ;i++)
System.out.print( Integer.toHexString(0x40000000 >> i) + " ");
output
40000000 20000000 10000000 8000000 4000000 2000000 1000000 800000

// 符號位爲1的右移
// 最高4位爲1000, 右移1位,變成1100也就是c,
for (int i = 0;i < 8 ;i++)
System.out.print( Integer.toHexString(0x80000000 >> i) + " ");
output
80000000 c0000000 e0000000 f0000000 f8000000 fc000000 fe000000 ff000000

上面的通用法則沒有錯,但是有一個限制,對int型,移位的位數不超過32,對long型,移位的位數不超過64。現在進行如下測試:
System.out.println(Integer.toHexString(0x80000000 >> 31));
// output: ffffffff
System.out.println(Integer.toHexString(0x80000000 >> 32));
// output: 80000000

0x80000000在右移31位後,每個位都成了1(也就是-1),按照這個想法,右移32位理所當然的還是-1,可是右移32位後,得到的結果卻又這個數本身。

通過對int,long類型數據左右移進行測試,發現:
[b]java對移位運算"a <<||>> b"的處理,首先做 b mod 32||64運算, 如果a是int型,取mod 32,如果a是double型,取mod 64,然後再使用上面提到的通用移位運算規則進行移位。[/b]

到這裏,就可以理解爲什麼在BitSet類中是
1L << bitIndex
這條語句,因爲熟悉jdk的Programer知道,再寫 1L << (bitIndex % 64) 對jdk來說是多餘的。

處理的規則發現了,但仍然有個疑問:
- jdk爲什麼這樣做? 雖然90%的程序員不會遇到這個問題。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章