轉自http://blog.csdn.net/candyguy...html
Java採用」2的補碼「(Two's Complement)編碼負數,它是一種數值的編碼方法,要分二步完成:第一步,每個二進制位都取相反值,0變成1,1變成0。好比,+8的二進制編碼是00001000,取反後就是11110111。第二步,將上一步獲得的值加1。11110111就變成11111000。因此,00001000的2的補碼就是11111000。也就是說,-8在計算機(8位機)中就是用11111000表示。關於「2的補碼」的詳細信息,請參考阮一峯的博文《關於2的補碼》,見附頁編碼
符號擴展(Sign Extension)用於在數值類型轉換時擴展二進制位的長度,以保證轉換後的數值和原數值的符號(正或負)和大小相同,通常用於較窄的類型(如byte)向較寬的類型(如int)轉換。擴展二進制位長度指的是,在原數值的二進制位左邊補齊若干個符號位(0表示正,1表示負)。.net
舉例來講,若是用6個bit表示十進制數10,二進制碼爲"00 1010",若是將它進行符號擴展爲16bits長度,結果是"0000 0000 0000 1010",即在左邊補上10個0(由於10是正數,符號爲0),符號擴展先後數值的大小和符號都保持不變;若是用10bits表示十進制數-15,使用「2的補碼」編碼後,二進制碼爲"11 1111 0001",若是將它進行符號擴展爲16bits,結果是"1111 1111 1111 0001",即在左邊補上6個1(由於-15是負數,符號爲1),符號擴展先後數值的大小和符號都保持不變。orm
Java中整型字面量
Java中int型字面量的書寫方式有如下幾種:htm
十進制方式,直接書寫十進制數字blog
八進制方式,格式以0打頭,例如012表示十進制10開發
十六進制方式,格式爲0x打頭,例如0xff表示十進制255=15x16^1+15x16^0部署
須要注意的是,在Java中012和0xff返回的都是int型數據,即長度是32位。get
Java的數值類型轉換規則
這個規則是《Java解惑》總結的:若是最初的數值類型是有符號的,那麼就執行符號擴展;若是是char類型,那麼無論它要被轉換成什麼類型,都執行零擴展。還有另一條規則也須要記住,若是目標類型的長度小於源類型的長度,則直接截取目標類型的長度。例如將int型轉換成byte型,直接截取int型的右邊8位。
(char類型無符號,所以執行零擴展)編譯器
連續三次類型轉換的表達式以下:
(int)(char)(byte)-1
int(32位) -> byte(8位)
-1是int型的字面量,根據「2的補碼」編碼規則,編碼結果爲0xffffffff,即32位所有置1。轉換成byte類型時,直接截取最後8位,因此byte結果爲0xff,對應的十進制值是-1.
byte(8位) -> char(16位)
因爲byte是有符號類型,因此在轉換成char型(16位)時須要進行符號擴展,即在0xff左邊連續補上8個1(1是0xff的符號位),結果是0xffff。因爲char是無符號類型,因此0xffff表示的十進制數是65535。
char(16位) -> int(32位)
因爲char是無符號類型,轉換成int型時進行零擴展,即在0xffff左邊連續補上16個0,結果是0x0000ffff,對應的十進制數是65535。
在進行類型轉換時,必定要了解表達式的含義,不能光靠感受。最好的方法是將你的意圖明確表達出來。
在將一個char型數值c轉型爲一個寬度更寬的類型時,而且不但願有符號擴展,能夠以下編碼:
int i = c & 0xffff;
上文曾提到過,0xffff是int型字面量,因此在進行&操做以前,編譯器會自動將c轉型成int型,即在c的二進制編碼前添加16個0,而後再和0xffff進行&操做,所表達的意圖是強制將前16置0,後16位保持不變。雖然這個操做不是必須的,可是明確表達了不進行符號擴展的意圖。
若是須要符號擴展,則能夠以下編碼:
int i = (short)c; //Cast causes sign extension
首先將c轉換成short類型,它和char是 等寬度的,而且是有符號類型,再將short類型轉換成int類型時,會自動進行符號擴展,即若是short爲負數,則在左邊補上16個1,不然補上16個0.
若是在將一個byte數值b轉型爲一個char時,而且不但願有符號擴展,那麼必須使用一個位掩碼來限制它:
char c = (char)(b & 0xff);
(b & 0xff)的結果是32位的int類型,前24被強制置0,後8位保持不變,而後轉換成char型時,直接截取後16位。這樣無論b是正數仍是負數,轉換成char時,都至關因而在左邊補上8個0,即進行零擴展而不是符號擴展。
若是須要符號擴展,則編碼以下:
char c = (char)b; //Sign extension is performed
此時爲了明確表達須要符號擴展的意圖,註釋是必須的。
實際上在數值類型轉換時,只有當遇到負數時纔會出現問題,根本緣由就是Java中的負數不是採用直觀的方式進行編碼,而是採用「2的補碼」方式,這樣的好處是加法和減法操做能夠同時使用加法電路完成,可是在開發時卻會遇到不少奇怪的問題,例如(byte)128的結果是-128,即一個大的正數,截斷後卻變成了負數。3.2節中引用了一些轉型規則,應用這些規則能夠很容地解決常見的轉型問題。
轉自 http://www.ruanyifeng.com/blo...
問一個基本的問題。
舉例來講,+8在計算機中表示爲二進制的1000,那麼-8怎麼表示呢?
很容易想到,能夠將一個二進制位(bit)專門規定爲符號位,它等於0時就表示正數,等於1時就表示負數。好比,在8位機中,規定每一個字節的最高位爲符號位。那麼,+8就是00001000,而-8則是10001000。
可是,隨便找一本《計算機原理》,都會告訴你,實際上,計算機內部採用2的補碼(Two's Complement)表示負數。
它是一種數值的轉換方法,要分二步完成:
第一步,每個二進制位都取相反值,0變成1,1變成0。好比,00001000的相反值就是11110111。
第二步,將上一步獲得的值加1。11110111就變成11111000。
因此,00001000的2的補碼就是11111000。也就是說,-8在計算機(8位機)中就是用11111000表示。
不知道你怎麼看,反正我以爲很奇怪,爲何要採用這麼麻煩的方式表示負數,更直覺的方式難道很差嗎?
昨天,我在一本書裏又看到了這個問題,而後就花了一點時間到網上找資料,如今總算完全搞明白了。
首先,要明確一點。計算機內部用什麼方式表示負數,實際上是無所謂的。只要可以保持一一對應的關係,就能夠用任意方式表示負數。因此,既然能夠任意選擇,那麼理應選擇一種最方便的方式。
2的補碼就是最方便的方式。它的便利體如今,全部的加法運算可使用同一種電路完成。
仍是以-8做爲例子。
假定有兩種表示方法。一種是直覺表示法,即10001000;另外一種是2的補碼錶示法,即11111000。請問哪種表示法在加法運算中更方便?
隨便寫一個計算式,16 + (-8) = ?
16的二進制表示是 00010000,因此用直覺表示法,加法就要寫成:
00010000
+10001000
---------
10011000
能夠看到,若是按照正常的加法規則,就會獲得10011000的結果,轉成十進制就是-24。顯然,這是錯誤的答案。也就是說,在這種狀況下,正常的加法規則不適用於正數與負數的加法,所以必須制定兩套運算規則,一套用於正數加正數,還有一套用於正數加負數。從電路上說,就是必須爲加法運算作兩種電路。
如今,再來看2的補碼錶示法。
00010000
+11111000
---------
100001000
能夠看到,按照正常的加法規則,獲得的結果是100001000。注意,這是一個9位的二進制數。咱們已經假定這是一臺8位機,所以最高的第9位是一個溢出位,會被自動捨去。因此,結果就變成了00001000,轉成十進制正好是8,也就是16 + (-8) 的正確答案。這說明了,2的補碼錶示法能夠將加法運算規則,擴展到整個整數集,從而用一套電路就能夠實現所有整數的加法。
在回答2的補碼爲何能正確實現加法運算以前,咱們先看看它的本質,也就是那兩個步驟的轉換方法是怎麼來的。
要將正數轉成對應的負數,其實只要用0減去這個數就能夠了。好比,-8其實就是0-8。
已知8的二進制是00001000,-8就能夠用下面的式子求出:
00000000
-00001000
---------
由於00000000(被減數)小於0000100(減數),因此不夠減。請回憶一下小學算術,若是被減數的某一位小於減數,咱們怎麼辦?很簡單,問上一位借1就能夠了。
因此,0000000也問上一位借了1,也就是說,被減數實際上是100000000,算式也就改寫成:
100000000
-00001000
---------
11111000
進一步觀察,能夠發現100000000 = 11111111 + 1,因此上面的式子能夠拆成兩個:
11111111
-00001000
---------
11110111
+00000001
---------
11111000
2的補碼的兩個轉換步驟就是這麼來的。
另:
+4:00000100
+3:00000011
+2:00000010
+1:00000001
0:00000000
-1:11111111
-2:11111110
-3:11111101
-4:11111100
觀察規律得出
實際上,咱們要證實的是,X-Y或X+(-Y)能夠用X加上Y的2的補碼完成。
Y的2的補碼等於(11111111-Y)+1。因此,X加上Y的2的補碼,就等於:
X-Y
= X + (11111111-Y) + 1
= X - Y + 100000000
= X - Y + 00000000
= X - Y
這就證實了,在正常的加法規則下,能夠利用2的補碼獲得正數與負數相加的正確結果。換言之,計算機只要部署加法電路和補碼電路,就能夠完成全部整數的加法。