理解java移位運算符


     移位運算符操作的對象就是二進制的位,可以單獨用移位運算符來處理int型整數。

 運算符       含義       例子      
<< 左移運算符,將運算符左邊的對象向左移動運算符右邊指定的位數(在低位補0) x<<3
>> "有符號"右移運算 符,將運算符左邊的對象向右移動運算符右邊指定的位數。使用符號擴展機制,也就是說,如果值為正,則在高位補0,如果值為負,則在高位補1. x>>3
>>> "無符號"右移運算 符,將運算符左邊的對象向右移動運算符右邊指定的位數。采用0擴展機制,也就是說,無論值的正負,都在高位補0. x>>>3

  

 

 

以int類型的6297為例,代碼如下:

[java] view plaincopy
  1. System.out.println(Integer.toBinaryString(6297));   
  2. System.out.println(Integer.toBinaryString(-6297));   
  3. System.out.println(Integer.toBinaryString(6297>>5));   
  4. System.out.println(Integer.toBinaryString(-6297>>5));   
  5. System.out.println(Integer.toBinaryString(6297>>>5));   
  6. System.out.println(Integer.toBinaryString(-6297>>>5));   
  7. System.out.println(Integer.toBinaryString(6297<<5));   
  8. System.out.println(Integer.toBinaryString(-6297<<5));  

 

  運行結果:

1100010011001
11111111111111111110011101100111
11000100
11111111111111111111111100111011
11000100
111111111111111111100111011
110001001100100000
11111111111111001110110011100000

注:x<<y 相當於 x*2;x>>y相當於x/2y
    從計算速度上講,移位運算要比算術運算快。
    如果x是負數,那么x>>>3沒有什么算術意義,只有邏輯意義。

 

在Think in Java中有這么一段話

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

 

這段話有兩個出處,一個是Java編程思想3.11移位操作符中出現,原話是“只有數值右端的低5位才有用”。一個是Java解惑中謎題27:變幻莫測的i值,原話是“移位操作符只使用其右操作數的低5位作為移位長度”。

弄清這句話首先需要弄清楚移位操作符,移位操作符是一個二元操作符,兩個操作數分別位於移位操作兩邊形如:左操作數 移位操作符 右操作數 這樣的結構,其含義是,將左操作數按照移位操作符指定的移位方向,進行右操作數指定的次數的移位。然后對照出處二,Java解惑中所描述的,就豁然開朗了。

首先,移位操作符能操作的數只有int類型和long類型,這個是指左操作數的類型。對於int類型而言,int在Java中占4字節,一共32位,也就是說,對於一個在Java中的int數據,做32次移位,那么這個int數據就完全變了,以左移為例,左移是補0,那么對於任意一個int類型數據,做32次移位,那么int數據變成32位全0的數據,Java不允許一次性移位左操作數的所有位,也就是右操作數不能大於32。於是回到上述的句子,其指的是右操作數的低5位,5位二進制所代表的最大值為2^5-1,為31,所以取右操作數的低5位,就是只看右操作數的二進制的低5位,其數值不會超過2^5次方,也就是int的32位。因此,移位操作符進行移位的實際次數,其實是右操作數2的次數。


對上面那段話的理解是:移位操作符操作的運算對象是二進制的“位”,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

//////////////////////////////////////////////////
移位運算符和按位運算符一樣,同屬於位運算符,因此移位運算符的位指的也是二進制位。它包括以下幾種:
左移位(<<):將操作符左側的操作數向左移動操作符右側指定的位數 。移動的規則是在二進制的低位補0。

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

無符號右移位(>>>):將操作符左側的操作數向右移動操作符右側指定的位數。移動的規則是,無論被操作數的符號是正是負,都在二進制位的高位補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=?呢?
這里就涉及到移位運算的另外一些規則:
byte、short、char在做移位運算之前,會被自動轉換為int類型,然后再進行運算。 byte、short、int、char類型的數據經過移位運算后結果都為int型。 long經過移位運算后結果為long型。

在左移位(<<)運算時,如果要移位的位數大於被操作數對應數據類型所能表示的最大位數,那么先將要求移位數對該類型所能表示的最大位數求余后,再將被操作數移位所得余數對應的數值,效果不變。

比如1<<35=1<&lt;(352)=1<<3=8。 對於有符號右移位(>>)運算和無符號右移位(>>>)運算,當要移位的位數大於被操作數對應數據類型所能表示的最大位數時,那么先將要求移位數對該類型所能表示的最大位數求余后,再將被操作數移位所得余數對應的數值,效果不變。。

比如100>>35=100>>(352)=100>>3=12。

另:

Java 的 Integer.toBinaryString 方法

public static String toBinaryString(int i) //以二進制(基數 2)無符號整數形式返回一個整數參數的字符串表示形式。 //如果參數為負,該無符號整數值為參數加上 2^32;否則等於該參數。
 System.out.println(Integer.toBinaryString(-1)) ; System.out.println(Integer.toBinaryString(2)) ; System.out.println(Integer.toBinaryString(1)) ;
 輸出: 11111111111111111111111111111111 11111111111111111111111111111110 1

結論輸出的是數字的二進制補碼。為什么說是以 二進制無符號整數形式 返回一個 整數類型的字符串,為什么 如果參數為負數,就要加上 232 次方?

因為Java里的int是有符號的,在內存中沒有正負之分,只有0/1,整數是用補碼表示的

正數補碼等於原碼
負數的補碼等於其絕對值的反碼+1,正好等於自身+2^32(對於4字節的整型來說)

-1 的補碼 就是 絕對值1 的反碼(按位取反) 11111111 11111111 11111111 11111110 再+1
等於 11111111 11111111 11111111 11111111

這樣正好能把最高位為1的數字用來表示負數,而最高位為0的數字表示非負數

10000000 00000000 00000000 00000000 => -2147483648 11111111 11111111 11111111 11111111 => -1 00000000 00000000 00000000 00000000 => 0 00000000 00000000 00000000 00000001 => 1 01111111 11111111 11111111 11111111 => 2147483647 

因此負數+2^32之后的二進制串,就是該負數內存中准確的存儲形式

 

 

參考、轉載:

http://blog.sina.cn/dpool/blog/s/blog_6f436a590100nc37.html?vt=4

https://segmentfault.com/q/1010000002535852

http://blog.sina.com.cn/s/blog_6ca0f5eb0102vlha.html

http://www.cnblogs.com/bluestorm/p/5795461.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM