您好,登錄后才能下訂單哦!
這篇文章主要講解了“Java原碼、補(bǔ)碼和反碼的詳細(xì)介紹”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Java原碼、補(bǔ)碼和反碼的詳細(xì)介紹”吧!
1.原碼、反碼和補(bǔ)碼
大家應(yīng)該都知道,數(shù)據(jù)在計(jì)算機(jī)中是以二進(jìn)制的形式存在的,比如 byte a = 6; byte b = -6
分為兩種情況來(lái)說(shuō),一種是正數(shù),一種是負(fù)數(shù);對(duì)于正數(shù)6來(lái)說(shuō),原碼就是0000 0110,反碼和補(bǔ)碼也是這個(gè);而對(duì)于-6來(lái)說(shuō),原碼就是1000 0110,這是為什么呢?因?yàn)?**位(最左邊的)是表示符號(hào),0表示正數(shù),1表示負(fù)數(shù);
不管是byte,short,int還是其他的數(shù)字,***位都是用來(lái)表示符號(hào)的,所以-6的原碼就是1000 0110,負(fù)數(shù)的反碼就是符號(hào)不變,其他的取反,就是1111 1001;負(fù)數(shù)的補(bǔ)碼就是在反碼的基礎(chǔ)上加1就行了,由于是二進(jìn)制的,是逢2進(jìn)1,所以補(bǔ)碼就是:1111 1010,;
注意:計(jì)算機(jī)中的加減運(yùn)算(計(jì)算機(jī)中只有加法,可以通過(guò)加法表示減法,就是用過(guò)補(bǔ)碼的形式,看下面栗子)指的是補(bǔ)碼之間的運(yùn)算!而且負(fù)數(shù)在計(jì)算機(jī)中是以補(bǔ)碼的形式存在并參與運(yùn)算的,如果要變?yōu)槭M(jìn)制,就首先需要變?yōu)樵a然后才能變?yōu)槭M(jìn)制或其他進(jìn)制的數(shù);
那么0怎么表示呢?我們可以簡(jiǎn)單看看:0 = 6-6 = 6+(-6)= [0000 0110]補(bǔ)+[1111 1010]補(bǔ)=[0000 0000]補(bǔ)=[0000 0000]原,那么有人要問(wèn)了,補(bǔ)碼1000 0000那又表示多少呢?再看一個(gè)簡(jiǎn)單的-1-127=(-1)
+(-127)= [1000 0001]原+[1111 1111]原 = [1111 1111]補(bǔ)+[1000 0001]補(bǔ) = [1000 0000]補(bǔ)=[0000 0000]原,兩個(gè)對(duì)比一下,如果都使用原碼的話同一個(gè)原碼[0000 0000]原可以表示兩個(gè)數(shù)0和-128,而用補(bǔ)碼的話卻可以一個(gè)補(bǔ)碼對(duì)應(yīng)單獨(dú)的一個(gè)數(shù),很明顯,一個(gè)補(bǔ)碼對(duì)應(yīng)一個(gè)數(shù)更符合我們的需求!!!
補(bǔ)充一下,對(duì)于負(fù)數(shù)來(lái)說(shuō),原碼和反碼之間相互轉(zhuǎn)化,試著理解著記憶:
原碼------>反碼:符號(hào)位不變,其他位取反 ;比如 [1000 0001]原 = [1111 1110]反
原碼------>補(bǔ)碼:符號(hào)位不變,其他位取反,然后+1;比如 [1000 0001]原 = [1111 1111]補(bǔ)
反碼------->原碼:符號(hào)位不變,其他位取反;比如 [1111 1110]反 = [1000 0001]原
反碼------->補(bǔ)碼:+1 ;比如 [1111 1110]反 = [1111 1111]補(bǔ)
補(bǔ)碼------->原碼:符號(hào)位不變,其他位取反,然后+1;比如 [1111 1111]補(bǔ) = [1000 0001]原
補(bǔ)碼--------->反碼:先變?yōu)樵a,然后變反碼;比如 [1111 1111]補(bǔ) =[1111 1110]反
這些都是基本的東西,只要記住在計(jì)算機(jī)中運(yùn)算的話,都是以補(bǔ)碼的形式,而且這里就會(huì)涉及到一個(gè)過(guò)程,畫一個(gè)簡(jiǎn)單的圖,計(jì)算機(jī)中運(yùn)算都是用補(bǔ)碼來(lái)進(jìn)行的;而中間的轉(zhuǎn)化過(guò)程計(jì)算機(jī)可以十分迅速的轉(zhuǎn)化,這個(gè)就不用我們操心;下面我們就看看那個(gè)運(yùn)算到底包括哪些運(yùn)算。。。
2.基本的運(yùn)算
說(shuō)起現(xiàn)實(shí)中的運(yùn)算,無(wú)非就是四則運(yùn)算,加減乘除,而對(duì)應(yīng)于計(jì)算機(jī)中也有加減乘除,加減已經(jīng)在上面說(shuō)了,可以用補(bǔ)碼的加法來(lái)實(shí)現(xiàn)加減,但是乘除呢?在這里我們就說(shuō)說(shuō)最簡(jiǎn)單的乘除法啊,乘以2和除以2這種,如果是乘除其他數(shù)還是比較復(fù)雜的,暫時(shí)我也沒有什么興趣研究,有興趣的小伙伴可以查查計(jì)算機(jī)中乘除法的實(shí)現(xiàn),你會(huì)沉迷其中不可自拔!
以byte類型來(lái)舉例,byte類型***位是符號(hào)位,所以范圍是在1111 1111到01111 1111之間,變成十進(jìn)制也就是-127到127,加上0000 0000這個(gè)原碼對(duì)應(yīng)兩個(gè)數(shù)0和-128,所以整個(gè)的范圍就是-128到127;
乘除也是分為兩大塊,正數(shù)和負(fù)數(shù);
2.1 正數(shù)乘2運(yùn)算(左移用<<表示)
我們看看一個(gè)簡(jiǎn)單的數(shù)(這里我正數(shù)也寫一下補(bǔ)碼):byte a = 5; 5的原碼為:[0000 0101]原=[0000 0101]補(bǔ) ;乘以2就等于10,原碼為[0000 1010]原=[0000 1010]補(bǔ)
看看這兩個(gè)補(bǔ)碼有什么關(guān)系?就是將5的補(bǔ)碼最右邊添加一個(gè)0,最左邊去掉一個(gè)0!***是將5的補(bǔ)碼看作一個(gè)整體,這個(gè)整體向左移動(dòng)一位,左邊超過(guò)的位數(shù)直接去掉,右邊空的位置添0
這個(gè)時(shí)候會(huì)有一個(gè)問(wèn)題,假如二進(jìn)制補(bǔ)碼是0100 0000,也就是64,向左移動(dòng)一位,你覺得是多少?答案是-128,按理來(lái)說(shuō)應(yīng)該是正數(shù)的128啊,為什么是負(fù)的呢?記住,這個(gè)移位操作是會(huì)覆蓋符號(hào)位的,往左移動(dòng)一位的補(bǔ)碼是1000 0000,注意,這里千萬(wàn)不要變成原碼,在***節(jié)中說(shuō)過(guò)了補(bǔ)碼為1000 0000的就是-128(這兩個(gè)補(bǔ)碼一定要注意點(diǎn),很特殊,0000 0000代表十進(jìn)制的0,1000 0000代表十進(jìn)制的-128!千萬(wàn)不要變成原碼比較,因?yàn)樗麄兊脑a都是0000 0000無(wú)法區(qū)分)
public void num() { byte a = 64; byte b = (byte) (a<<1); System.out.println(b);//-128 }
2.2 正數(shù)除2運(yùn)算(右移用>>表示)
既然往左移動(dòng)一位是乘以2,那么往右移動(dòng)一位肯定是除以2了!但是記住一個(gè)規(guī)律,往右移動(dòng)的話,右邊超出來(lái)的部分去掉,左邊空出來(lái)的位置添加和符號(hào)位相同的數(shù)!(記住了規(guī)律這個(gè)負(fù)數(shù)的右移一樣的)
舉個(gè)例子,65的補(bǔ)碼0100 0001,向右移動(dòng)一位,補(bǔ)碼應(yīng)該是0010 0000,記住,此時(shí)最左邊的0是根據(jù)符號(hào)位是0才添加的0,是正數(shù),右移后的原碼和補(bǔ)碼一樣,那么變成十進(jìn)制應(yīng)該是32,這里可以看出一個(gè)大于0的奇數(shù)右移一位的結(jié)果就是除以2然后向下取整,偶數(shù)的話直接就是除以2了
public void num() { byte a = 64; byte b = (byte) (a<<1); System.out.println(b);//-128 }
2.3 負(fù)數(shù)乘2運(yùn)算(<<)
正數(shù)其實(shí)比較容易,但是負(fù)數(shù)的話就稍微麻煩一點(diǎn)!例如-127的補(bǔ)碼是1000 0001,左移一位的補(bǔ)碼0000 0010,由于這個(gè)補(bǔ)碼是正的,所以原碼也是這個(gè),變成十進(jìn)制就是2,有沒有覺得特別有意思,哈哈哈!知道為什么嗎?因?yàn)閎yte的范圍是-128到127啊,只要是超過(guò)了這個(gè)范圍的就會(huì)變成你想不到的數(shù)!
再舉個(gè)沒有超過(guò)范圍的例子,-6的補(bǔ)碼是1111 1010,左移一位的補(bǔ)碼就是1111 0100,由于是負(fù)的,變成原碼為1000 1100,也就是對(duì)應(yīng)十進(jìn)制的-12,這個(gè)結(jié)果和想象的一樣!
2.4 負(fù)數(shù)除2運(yùn)算(>>)
記住在2.2中說(shuō)的一句話,向右移動(dòng)的話,最右邊超過(guò)的部分直接去掉,左邊空出來(lái)的位置填上和符號(hào)位相同的數(shù)!說(shuō)起來(lái)很抽象,舉個(gè)栗子:-6的補(bǔ)碼是1111 1010,往右移動(dòng)一個(gè)位置的補(bǔ)碼就是1111 1101,是負(fù)的,變成原碼就知道對(duì)應(yīng)的十進(jìn)制是多少了。。。。
2.5.無(wú)符號(hào)右移(>>>)
本來(lái)都說(shuō)了正負(fù)數(shù)的左移和右移應(yīng)該就說(shuō)完了,但是呢,還有一個(gè)比較特殊的運(yùn)算方式,就是無(wú)符號(hào)右移(注意只有無(wú)符號(hào)右移,沒有無(wú)符號(hào)左移啊!),簡(jiǎn)單的來(lái)說(shuō)就是不管正數(shù)負(fù)數(shù),只要是右移的話,最右邊超過(guò)的部分直接丟掉,左邊空出來(lái)的位置都添0就ok了!
好像也沒什么可說(shuō)的,簡(jiǎn)單舉個(gè)栗子吧!-6的補(bǔ)碼是1111 1010,無(wú)符號(hào)右移一位的補(bǔ)碼就是0111 1101,正的,原碼和補(bǔ)碼一樣,所以對(duì)應(yīng)的十進(jìn)制是應(yīng)該是125,然而實(shí)際情況有點(diǎn)問(wèn)題,代碼如下:
@org.junit.Test public void num() { byte a = -6; byte b = (byte) (a>>>1); System.out.println(b);//-3 }
打印的結(jié)果為什么是-3呢?,這里就有一個(gè)小小的細(xì)節(jié)操作,在進(jìn)行右移操作的時(shí)候,首先會(huì)將該byte類型的數(shù)變成int類型的,對(duì)int類型的變?cè)a,然后變補(bǔ)碼,移位操作之后,取后8位變?yōu)閎yte類型,然后變?cè)a,***轉(zhuǎn)十進(jìn)制。。。。是不是賊麻煩!還是以上面的-6為栗子,-6要進(jìn)行無(wú)符號(hào)右移,所以-6的原碼應(yīng)該是32位的
10000000 00000000 00000000 00000110 //原碼 11111111 11111111 11111111 11111010//補(bǔ)碼 011111111 11111111 11111111 1111101//無(wú)符號(hào)右移一位 11111101//取后八位,就是byte類型的補(bǔ)碼 10000011//byte類型原碼,對(duì)應(yīng)十進(jìn)制是-3
3.簡(jiǎn)單總結(jié)一下
由于我們是用一個(gè)byte類型的為例,這也是為了方便舉例子,不然用個(gè)int類型的,隨便一個(gè)數(shù)寫出原碼都是一大串,看著都眼花。。。其實(shí)byte類型的移位運(yùn)算弄清楚了,其他的類型一樣的,看了這么多,不知道大家有沒有總結(jié)出來(lái)一點(diǎn)規(guī)律,我就說(shuō)說(shuō)我的理解吧!
首先,我們要明確當(dāng)前的數(shù)是一個(gè)什么類型,進(jìn)行移位操作之后會(huì)不會(huì)超出這個(gè)類型的范圍,如果超出了,我們是不能直接得出乘以2或者除以2這種簡(jiǎn)單的結(jié)論的,會(huì)得出一個(gè)意想不到的數(shù)字;
然后,如果移位操作之后沒有超過(guò)當(dāng)前類型的范圍,那么就大膽的說(shuō)左移一位是乘以2,右移一位是除以2向下取整吧!!!
再然后,對(duì)于一個(gè)正數(shù),左移一位就是***位去掉,***位添0;右移一位***位添加和符號(hào)位一樣的數(shù),***位去掉;對(duì)于負(fù)數(shù)而言,也是一樣的,就不多說(shuō)了
***,就是無(wú)符號(hào)右移,這里要注意先要變成int類型的二進(jìn)制原碼,變補(bǔ)碼,然后進(jìn)行移位操作,截取后8位為我們需要的byte類型的補(bǔ)碼,再變?cè)a,***就是變成十進(jìn)制的了。。。
4."或"、"與"、"非"、"異或"
請(qǐng)注意“或”、“與”、“非”和java中的||、&&、!別弄混淆了,java中的這幾個(gè)是用來(lái)進(jìn)行邏輯判斷的,而我們這里的“或”“與”“異或”這幾個(gè)是用來(lái)計(jì)算二進(jìn)制的,完全沒有什么相關(guān),雖然寫法有點(diǎn)類似,“或”用一根豎線表示|,與用一個(gè)&表示,非用~表示,"異或"用^表示,下面就簡(jiǎn)單說(shuō)說(shuō)他們的作用:
或:在二進(jìn)制中,兩個(gè)操作數(shù)進(jìn)行或操作,只要有一個(gè)為1,結(jié)果就為1,否則就為0;舉個(gè)例子,-6|3,首先將各自都變?yōu)檠a(bǔ)碼,也就是變?yōu)?1111 1011)|(0000 0011),根據(jù)下圖,***計(jì)算的補(bǔ)碼為1111 1011,變?yōu)樵a為1000 0101,對(duì)應(yīng)十進(jìn)制的-5,所以-6|3的結(jié)果就是-5!很簡(jiǎn)單吧,現(xiàn)在應(yīng)該知道操作數(shù)是什么了吧!
public void num() { byte a = -6; System.out.println(~a);//5 }
與:兩個(gè)操作數(shù)同時(shí)為1,結(jié)果才是1,否則為0;
異或:看這個(gè)名字就知道了,兩個(gè)操作數(shù)不同結(jié)果就是1,否則為0;
非:就是對(duì)自己取反(符號(hào)位也要取反),用法如下,因?yàn)?6的補(bǔ)碼是1111 1010,取反之后的補(bǔ)碼0000 0101,對(duì)應(yīng)十進(jìn)制的5
public void num() { byte a = -6; System.out.println(~a);//5 }
感謝各位的閱讀,以上就是“Java原碼、補(bǔ)碼和反碼的詳細(xì)介紹”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Java原碼、補(bǔ)碼和反碼的詳細(xì)介紹這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。