一 Java 位運算
1.表示方法:
在Java語言中,二進制數使用補碼表示,最高位為符號位,正數的符號位為0,負數為1。補碼的表示需要滿足如下要求。
(1)正數的最高位為0,其余各位代表數值本身(二進制數)。
(2)對於負數,通過對該數絕對值的補碼按位取反,再對整個數加1。
2.位運算符
位運算表達式由操作數和位運算符組成,實現對整數類型的二進制數進行位運算。位運算符可以分為邏輯運算符(包括~、&、|和^)及移位運算符(包括>>、<<和>>>)。
1)左移位運算符(<<)能將運算符左邊的運算對象向左移動運算符右側指定的位數(在低位補0)。
2)“有符號”右移位運算符(>>)則將運算符左邊的運算對象向右移動運算符右側指定的位數。 “有符號”右移位運算符使用了“符號擴展”:若值為正,則在高位插入0;若值為負,則在高位插入1。
3)Java也添加了一種“無符號”右移位運算符(>>>),它使用了“零擴展”:無論正負,都在高位插入0。這一運算符是C或C++沒有的。
4)若對char,byte或者short進行移位處理,那麼在移位進行之前,它們會自動轉換成一個int。 只有右側的5個低位才會用到。這樣可防止我們在一個int數裡移動不切實際的位數。 若對一個long值進行處理,最後得到的結果也是long。此時只會用到右側的6個低位,防止移動超過long值裡現成的位數。 但在進行“無符號”右移位時,也可能遇到一個問題。若對byte或short值進行右移位運算,得到的可能不是正確的結果(Java 1.0和Java 1.1特別突出)。 它們會自動轉換成int類型,並進行右移位。但“零擴展”不會發生,所以在那些情況下會得到-1的結果。
在進行位運算時,需要注意以下幾點。
(1)>>>和>>的區別是:在執行運算時,>>>運算符的操作數高位補0,而>>運算符的操作數高位移入原來高位的值。
(2)右移一位相當於除以2,左移一位(在不溢出的情況下)相當於乘以2;移位運算速度高於乘除運算。
(3)若進行位邏輯運算的兩個操作數的數據長度不相同,則返回值應該是數據長度較長的數據類型。
(4)按位異或可以不使用臨時變量完成兩個值的交換,也可以使某個整型數的特定位的值翻轉。
(5)按位與運算可以用來屏蔽特定的位,也可以用來取某個數型數中某些特定的位。
(6)按位或運算可以用來對某個整型數的特定位的值置l。
3.位運算符的優先級
~的優先級最高,其次是<<、>>和>>>,再次是&,然後是^,優先級最低的是|。
二, 按位異或運算符^
參與運算的兩個值,如果兩個相應位相同,則結果為0,否則為1。即:0^0=0, 1^0=1, 0^1=1, 1^1=0
例如:10100001^00010001=10110000
0^0=0,0^1=1 0異或任何數=任何數
1^0=1,1^1=0 1異或任何數-任何數取反
任何數異或自己=把自己置0
(1)按位異或可以用來使某些特定的位翻轉,如對數10100001的第2位和第3位翻轉,可以將數與00000110進行按位異或運算。 10100001^00000110=10100111 //1010 0001 ^ 0x06 = 1010 0001 ^ 6
(2)通過按位異或運算,可以實現兩個值的交換,而不必使用臨時變量。
例如交換兩個整數a,b的值,可通過下列語句實現:
a=10100001,b=00000110
a=a^b; //a=10100111
b=b^a; //b=10100001
a=a^b; //a=00000110
(3)異或運算符的特點是:數a兩次異或同一個數b(a=a^b^b)仍然為原值a.
三,Java 中除了二進制的表示方法:
由於數據在計算機中的表示,最終以二進制的形式存在,所以有時候使用二進制,可以更直觀地解決問題。
但,二進制數太長了。比如int 類型占用4個字節,32位。比如100,用int類型的二進制數表達將是:
0000 0000 0000 0000 0110 0100
面對這麼長的數進行思考或操作,沒有人會喜歡。因此,C,C++,以及java中 沒有提供在代碼直接寫二進制數的方法。
八進制數的表達方法
如何表達一個八進制數呢?如果這個數是 876,我們可以斷定它不是八進制數,因為八進制數中不可能出7以上的阿拉伯數字。但如果這個數是123、是567,或12345670,那麼它是八進制數還是10進制數,都有可能。
所以規定,一個數如果要指明它采用八進制,必須在它前面加上一個0,如:123是十進制,但0123則表示采用八進制。這就是八進制數的表達方法。 現在,對於同樣一個數,比如是100,我們在代碼中可以用平常的10進制表達,例如在變量初始化時:
int a = 100;
我們也可以這樣寫:
int a = 0144; //0144是八進制的100;一個10進制數如何轉成8進制。
千萬記住,用八進制表達時,你不能少了最前的那個0。否則計算機會通通當成10進制。不過,有一個地方使用八進制數時,卻不能使用加0,那就是我們前面學的用於表達字符的“轉義符”表達法。
十六進制數的表達方法
如果不使用特殊的書寫形式,16進制數也會和10進制相混。隨便一個數:9876,就看不出它是16進制或10進制。
16進制數必須以 0x開頭。比如 0x1表示一個16進制數。而1則表示一個十進制。另外如:0xff,0xFF,0X102A,等等。其中的x也也不區分大小寫。(注意:0x中的0是數字0,而不是字母O)
以下是一些用法示例:
int a = 0x100F;
int b = 0x70 + a;
最後一點很重要,10進制數有正負之分,比如12表示正12,而-12表示負 12,;但8進制和16進制只能用來表達無符號的正整數,如果你在代碼中裡:-078,或者寫:-0xF2,編譯器並不把它當成一個負數。
代碼示例:
package 位運算; public class Test { public static void main(String[] args) { byte b =5; int i = 4; long l = 10; judgeIndex(); System.out.println(b << 2);// 運行結果是20 System.out.println(i << 2);// 運行結果是16 System.out.println(l >> 2);// 運行結果是2 // 1、左移( << ) // 0000 0000 0000 0000 0000 0000 0000 0101 然後左移2位後,低位補0:// // 0000 0000 0000 0000 0000 0000 0001 0100 換算成10進制為20 System.out.println(5 << 2);// 運行結果是20 // 2、右移( >> ) 高位補符號位 // 0000 0000 0000 0000 0000 0000 0000 0101 然後右移2位,高位補0: // 0000 0000 0000 0000 0000 0000 0000 0001 System.out.println(5 >> 2);// 運行結果是1 // 3、無符號右移( >>> ) 高位補0 // 例如 -5換算成二進制後為:0101 取反加1為1011 // 1111 1111 1111 1111 1111 1111 1111 1011 // 我們分別對5進行右移3位、 -5進行右移3位和無符號右移3位: System.out.println(5 >> 3);// 結果是0 System.out.println(-5 >> 3);// 結果是-1 System.out.println(-5 >>> 3);// 結果是536870911 // 4、位與( & ) // 位與:第一個操作數的的第n位於第二個操作數的第n位如果都是1,那麼結果的第n為也為1,否則為0 System.out.println(5 & 3);// 結果為1 System.out.println(4 & 1);// 結果為0 // 5、位或( | ) // 第一個操作數的的第n位於第二個操作數的第n位 只要有一個是1,那麼結果的第n為也為1,否則為0 System.out.println(5 | 3);// 結果為7 // 6、位異或( ^ ) // 第一個操作數的的第n位於第二個操作數的第n位 相反,那麼結果的第n為也為1,否則為0 System.out.println(5 ^ 3);//結果為6 // 7、位非( ~ ) // 操作數的第n位為1,那麼結果的第n位為0,反之。 System.out.println(~5);// 結果為-6 } //給一個64位的整型和二進制特定位編號,判斷該特定位是1還是0 public static void judgeIndex(){ long a = 123;long c=0; int b=4;//判斷第四位是1還是0 c=a>>b; a=c&1; System.out.println("c="+c+" "+"a="+a); //c=7 a=1 } }
運行結果:
c=7 a=1
20
16
2
20
1
0
-1
536870911
1
0
7
6
-6