二進制
正整數的二進制表示 (假定類型是byte)
正整數的二進制表示與此類似, 只是在十進制中,每個位置可以有10個數字,從0到9,但在二進制中,每個位置只能是0或1。
例如: 0000 1010 ==> 10
負整數的二進制表示 (假定類型是byte)
十進制的負數表示就是在前面加一個負數符號 -,例如-123。但二進制如何表示負數呢?
其實概念是類似的,二進制使用最高位表示符號位,用1表示負數,用0表示正數。
但負數表示不是簡單的將最高位變為1,比如說:
-
-
byte a = -1,如果只是將最高位變為1,二進制應該是10000001,但實際上,它應該是11111111。
-
byte a=-127,如果只是將最高位變為1,二進制應該是11111111,但實際上,它卻應該是10000001。
-
和我們的直覺正好相反,這是什么表示法?這種表示法稱為補碼表示法,而符合我們直覺的表示稱為原碼表示法,補碼表示就是在原碼表示的基礎上取反然后加1。取反就是將0變為1,1變為0。
負數的二進制表示就是對應的正數的補碼表示,比如說:
-
-1:1的原碼表示是00000001,取反是11111110,然后再加1,就是11111111。
-
-2:2的原碼表示是00000010,取反是11111101,然后再加1,就是11111110
-
-127:127的原碼表示是01111111,取反是10000000,然后再加1,就是10000001。
給定一個負數二進制表示,要想知道它的十進制值,可以采用相同的補碼運算。比如:10010010,首先取反,變為01101101,然后加1,結果為01101110,它的十進制值為110,所以原值就是-110。
byte類型,正數最大表示是01111111,即127,負數最大表示是10000000,即-128,表示范圍就是 -128到127。其他類型的整數也類似,負數能多表示一個數。
負整數為什么采用補碼呢?
負整數為什么要采用這種奇怪的表示形式呢?原因是:只有這種形式,計算機才能實現正確的加減法。
計算機其實只能做加法,1-1其實是1+(-1)。如果用原碼表示,計算結果是不對的。比如說:
1 -> 00000001
-1 -> 10000001
+ ------------------
-2 -> 10000010
用符合直覺的原碼表示,1-1的結果是-2。
如果是補碼表示:
1 -> 00000001
-1 -> 11111111
+ ------------------
0 -> 00000000
結果是正確的。
再比如,5-3:
5 -> 00000101
-3 -> 11111101
+ ------------------
2 -> 00000010
結果也是正確的。
就是這樣的,看上去可能比較奇怪和難以理解,但這種表示其實是非常嚴謹和正確的。
理解了二進制加減法,我們就能理解為什么正數的運算結果可能出現負數了。當計算結果超出表示范圍的時候,最高位往往是1,然后就會被看做負數。比如說,127+1:
127 -> 01111111
1 -> 00000001
+ ------------------
-128 ->10000000
計算結果超出了byte的表示范圍,會被看做-128。
補碼的好處
以 +1 和 -1 作加法運算為例,如下圖所示:

相信你已經發現,1 + (-1) 這樣的加法運算只要將二進制數相加,然后-1的末位就會變成2,根據逢2進1機制,從右至左依次所有位都會變成0。
最后,最左端的符號位也會進位1變成0,丟棄溢出的1,就得到最后的結果0的二進制表示32個0。
對照本節開頭的圖,會發現所有的減法都可以轉換成二進制位的加法運算:1-2 可以轉換成1+(-2),(-1)-(-2)可以轉換成-1+2……
這跟數學中的表示是一樣的,而且非常地方便計算(很多計算機科學家都是從數學領域轉入計算機工程,所以在很多細微之處的都能見到數學的影子)。因此,現代計算機硬件結構實際上只設計了加法器,大部分的減法其實都是轉換成加法后再運算。
備注:
以正數的二進制數表示為基准,負數的表示只改變符號位,這樣的表示方式就是原碼。因此,正數的表示方式都是原碼。
反碼就是將原碼除符號位以外的值全部取反,原來是1的變為0,原來是0的變為1。
補碼就是在反碼的基礎上,在二進制數的右端末位加1(逢2進1)。
小結
正數的原碼和反碼和補碼都一致;負數的原碼是正數的符號位取反;負數的反碼是原碼的非符號位取反;負數的補碼是反碼加1。
位運算
-
左移:操作符為<<,向左移動,右邊的低位補0,高位的就舍棄掉了,將二進制看做整數,左移1位就相當於乘以2。
-
無符號右移:操作符為>>>,向右移動,右邊的舍棄掉,左邊補0。
-
有符號右移:操作符為>>,向右移動,右邊的舍棄掉,左邊補什么取決於原來最高位是什么,原來是1就補1,原來是0就補0,將二進制看做整數,右移1位相當於除以2。
邏輯與或
兩種邏輯與(&&和&)的運算規則基本相同,兩種邏輯或(|| 和 |)的運算規則也基本相同。 &和|運算是把邏輯表達式全部計算完,而&&和||運算具有短路計算功能。
所謂短路計算,是指系統從左至右進行邏輯表達式的計算,一旦出現計算結果已經確定的情況,則計算過程即被終止。 對於&&運算來說,只要運算符左端的值為false,則因無論運算符右端的值為true或為false,其最終結果都為false。 所以,系統一旦判斷出&&運算符左端的值為false,則系統將終止其后的計算過程; 對於 || 運算來說,只要運算符左端的值為true,則因無論運算符右端的值為true或為false,其最終結果都為true。 所以,系統一旦判斷出|| 運算符左端的值為true,則系統將終止其后的計算過程。
小技巧
⑴ 乘法除法:n * 2 等價於 n << 1; n * 5 等價於 n << 2 + 1; n / 2 等價於 n >> 1。
備注:JVM執行時會自動轉化,大部分其它高級語言的編譯器會做類似優化轉換,所以除非有特殊的理由,否則別這么寫。
⑵ 取低位:n & 0x0000FFFF;取高位:n & 0xFFFF0000。
⑶ 奇偶判斷:n & 1,等於0為偶,等於1為奇。
⑷ 正負判斷:(n >>> 31) & 1,等於0為正,等於1為負。
⑸ 取余:n % m ,如m為2的冪次方,可用(n & (m - 1))替代。
參考:老馬說編程

