char,byte或者short進行移位處理

 在Think in Java中有這麼一段話“對char,byte或者short進行移位處理,那麼在移位進行之前,它們會自動轉換成一個int。只有右側的5個低位纔會有用。這樣可防止我們在一個int數裏移動不切實際的位數。若對一個long值進行處理,最後得到的結果也是long。此時只會用到右側的6個低位,防止移動超過long值裏現成的位數。”

 

對上面那段話的理解是:移位操作符操作的運算對象是二進制的“位”,int類型是32位也就是2的5次冪 !如果移32位以上,那麼原來的數的信息會全部丟失,這樣也就沒有什麼意義了!所以上面的“只有右側的5個低位纔會有用”說的是:移位操作符右端的那個數(化成二進制)的低5位纔有用,即 
X < <y; 
是指y的低5位纔有用,即不能大於32。 而對於long型也是同樣的道理!

因此,如果對一個int 型,進行移位,X < <y; 當y小於32時,移位後的結果一般都在我們的預料當中;而如果y大於32時,由於移位超出了int所能表示的範圍,這時就先把y化成二進制數,然後取該二進制數右端的低5位,再把這5位化成十進制,此時的這個十進制就是要對X移動的位數。

例如:         int int a=140;   
                     a << 34

                   System.out.println(Integer.toBinaryString(a << b));

上面那兩個語句的執行過程是:先把a化成二進制數:10001100

執行語句 a << 34   對a左移32位時,先把 34化成二進制:100010,對該二進制數取右邊5位,即00010,化成十進制數爲2,所以實際上是對a左移兩位。現在,地球人都會知道上面程序的輸出結果是:1000110000

//////////////////////////////////////////////////

移位運算符和按位運算符一樣,同屬於位運算符,因此移位運算符的位指的也是二進制位。它包括以下幾種:

  1. 左移位(<<):將操作符左側的操作數向左移動操作符右側指定的位數。移動的規則是在二進制的低位補0。
  2. 有符號右移位(>>):將操作符左側的操作數向右移動操作符右側指定的位數。移動的規則是,如果被操作數的符號爲正,則在二進制的高位補0;如果被操作數的符號爲負,則在二進制的高位補1。
  3. 無符號右移位(>>>):將操作符左側的操作數向右移動操作符右側指定的位數。移動的規則是,無論被操作數的符號是正是負,都在二進制位的高位補0。


注意,移位運算符不存在“無符號左移位(<<<)”一說。與按位運算符一樣,移位運算符可以用於byte、short、int、long等整數類型,和字符串類型char,但是不能用於浮點數類型float、double;當然,在Java5.0及以上版本中,移位運算符還可用於byte、short、int、long、char對應的包裝器類。我們可以參照按位運算符的示例寫一個測試程序來驗證,這裏就不再舉例了。

與按位運算符不同的是,移位運算符不存在短路不短路的問題。

寫到這裏就不得不提及一個在面試題中經常被考到的題目:

引用
請用最有效率的方法計算出2乘以8等於幾?


這裏所謂的最有效率,實際上就是通過最少、最簡單的運算得出想要的結果,而移位是計算機中相當基礎的運算了,用它來實現準沒錯了。左移位“<<”把被操作數每向左移動一位,效果等同於將被操作數乘以2,而2*8=(2*2*2*2),就是把2向左移位3次。因此最有效率的計算2乘以8的方法就是“2<<3”。

最後,我們再來考慮一種情況,當要移位的位數大於被操作數對應數據類型所能表示的最大位數時,結果會是怎樣呢?比如,1<<35=?呢?

這裏就涉及到移位運算的另外一些規則:

  1. byte、short、char在做移位運算之前,會被自動轉換爲int類型,然後再進行運算。
  2. byte、short、int、char類型的數據經過移位運算後結果都爲int型。
  3. long經過移位運算後結果爲long型。
  4. 在左移位(<<)運算時,如果要移位的位數大於被操作數對應數據類型所能表示的最大位數,那麼先將要求移位數對該類型所能表示的最大位數求餘後,再將被操作數移位所得餘數對應的數值,效果不變。比如1<<35=1<<(35%32)=1<<3=8。
  5. 對於有符號右移位(>>)運算和無符號右移位(>>>)運算,當要移位的位數大於被操作數對應數據類型所能表示的最大位數時,那麼先將要求移位數對該類型所能表示的最大位數求餘後,再將被操作數移位所得餘數對應的數值,效果不變。。比如100>>35=100>>(35%32)=100>>3=12。


下面的測試代碼驗證了以上的規律:

Java代碼 複製代碼
  1. public abstract class Test {   
  2.     public static void main(String[] args) {   
  3.         System.out.println("1 << 3 = " + (1 << 3));   
  4.         System.out.println("(byte) 1 << 35 = " + ((byte1 << (32 + 3)));   
  5.         System.out.println("(short) 1 << 35 = " + ((short1 << (32 + 3)));   
  6.         System.out.println("(char) 1 << 35 = " + ((char1 << (32 + 3)));   
  7.         System.out.println("1 << 35 = " + (1 << (32 + 3)));   
  8.         System.out.println("1L << 67 = " + (1L << (64 + 3)));   
  9.         // 此處需要Java5.0及以上版本支持   
  10.         System.out.println("new Integer(1) << 3 = " + (new Integer(1) << 3));   
  11.         System.out.println("10000 >> 3 = " + (10000 >> 3));   
  12.         System.out.println("10000 >> 35 = " + (10000 >> (32 + 3)));   
  13.         System.out.println("10000L >>> 67 = " + (10000L >>> (64 + 3)));   
  14.     }   
  15. }  
[java] view plaincopy
  1. public abstract class Test { public static void main(String[] args) { System.out.println("1 << 3 = " + (1 << 3)); System.out.println("(byte) 1 << 35 = " + ((byte1 << (32 + 3))); System.out.println("(short) 1 << 35 = " + ((short1 << (32 + 3))); System.out.println("(char) 1 << 35 = " + ((char1 << (32 + 3))); System.out.println("1 << 35 = " + (1 << (32 + 3))); System.out.println("1L << 67 = " + (1L << (64 + 3))); // 此處需要Java5.0及以上版本支持 System.out.println("new Integer(1) << 3 = " + (new Integer(1) << 3)); System.out.println("10000 >> 3 = " + (10000 >> 3)); System.out.println("10000 >> 35 = " + (10000 >> (32 + 3))); System.out.println("10000L >>> 67 = " + (10000L >>> (64 + 3))); } }  


運行結果:

  1. 1 << 3 = 8
  2. (byte) 1 << 35 = 8
  3. (short) 1 << 35 = 8
  4. (char) 1 << 35 = 8
  5. 1 << 35 = 8
  6. 1L << 67 = 8
  7. new Integer(1) << 3 = 8
  8. 10000 >> 3 = 1250
  9. 10000 >> 35 = 1250
  10. 10000L >>> 67 = 1250
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章