真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

JAVA中如何實(shí)現(xiàn)位運(yùn)算

這篇文章將為大家詳細(xì)講解有關(guān)JAVA中如何實(shí)現(xiàn)位運(yùn)算,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

在嘉善等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專(zhuān)注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計(jì)、做網(wǎng)站 網(wǎng)站設(shè)計(jì)制作按需搭建網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站建設(shè),全網(wǎng)營(yíng)銷(xiāo)推廣,成都外貿(mào)網(wǎng)站建設(shè)公司,嘉善網(wǎng)站建設(shè)費(fèi)用合理。

一、在計(jì)算機(jī)中數(shù)據(jù)是如何進(jìn)行計(jì)算的?

1.1:java中的byte型數(shù)據(jù)取值范圍

我們最開(kāi)始學(xué)習(xí)java的時(shí)候知道,byte類(lèi)型的數(shù)據(jù)占了8個(gè)bit位,每個(gè)位上或0或1,左邊第一位表示符號(hào)位,符號(hào)位如果為1表示負(fù)數(shù),為0則表示正數(shù),因此要推算byte的取值范圍,只需要讓數(shù)值位每一位上都等于1即可。

我們來(lái)用我們的常規(guī)思維來(lái)分析下byte類(lèi)型的取值范圍:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖1

如果按照這種思路來(lái)推算,七個(gè)1的二進(jìn)制數(shù)轉(zhuǎn)換為十進(jìn)制是127,算上符號(hào)位,取值范圍應(yīng)為:-127~+127,但事實(shí)上我們知道,byte的取值范圍是-128~127,這里先打個(gè)問(wèn)號(hào),接著往下看。

現(xiàn)在讓我們計(jì)算下byte類(lèi)型的7加上byte類(lèi)型的-2是多少:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖2

誒?跟我們預(yù)想的不一樣,因?yàn)槲覀兪侵?和-2的和應(yīng)該是5才對(duì),結(jié)果應(yīng)該表示為:00000101,但事實(shí)上通過(guò)圖2的結(jié)果來(lái)看確實(shí)跟預(yù)想的不一樣,所以計(jì)算機(jī)在做計(jì)算的時(shí)候,肯定不是表面上的符號(hào)位+數(shù)值位的方式進(jìn)行的計(jì)算的。

1.2:原碼,反碼,補(bǔ)碼

我們先來(lái)看下定義:

? 原碼定義:符號(hào)位加后面的數(shù)值,比如圖2里的00000111和10000010都是原碼,原碼比較簡(jiǎn)單,就是我們?cè)谏厦鎲渭兝斫馍系脑怠?/p>

? 反碼定義:正數(shù)的反碼就是它的原碼,負(fù)數(shù)的反碼符號(hào)位不變,其余數(shù)值位全部按位取反,例如:

00000111的反碼:00000111

10000010的反碼:11111101

? 補(bǔ)碼定義:同樣的,正數(shù)的補(bǔ)碼仍然等于它的原碼本身,負(fù)數(shù)的補(bǔ)碼等于它自己的反碼+1,例如:

00000111的補(bǔ)碼:00000111

10000010的補(bǔ)碼:11111110

? 總結(jié):正數(shù)的原碼、反碼、補(bǔ)碼完全一致,負(fù)數(shù)的反碼等于它原碼的數(shù)值位按位取反,負(fù)數(shù)的補(bǔ)碼等于它的反碼+1

現(xiàn)在讓我們用反碼的方式來(lái)計(jì)算下圖2中的式子:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖3

利用數(shù)值的反碼計(jì)算出的結(jié)果已經(jīng)很接近正確答案了,+4的反碼等于它的原碼,現(xiàn)在只需要讓它+1就是正確答案,還記得補(bǔ)碼的定義嗎?負(fù)數(shù)的補(bǔ)碼等于它的反碼+1,那現(xiàn)在讓我們用補(bǔ)碼做下計(jì)算試試?

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖4

ok,我們發(fā)現(xiàn),用它們的補(bǔ)碼做加法,得到的數(shù)值就是我們想要的正確答案,事實(shí)上,計(jì)算機(jī)并沒(méi)有減法運(yùn)算器,所有的減法運(yùn)算,都是以一個(gè)正數(shù)加上一個(gè)負(fù)數(shù)的形式來(lái)交給加法運(yùn)算器計(jì)算的,由于負(fù)數(shù)的符號(hào)位為1,雖然我們?nèi)耸侵浪暮x,但是作為計(jì)算機(jī),它是不知道第一位是符號(hào)位的,它要做的就僅僅是讓兩個(gè)數(shù)相加而已,正是因?yàn)槿绱?,我們才不能?jiǎn)簡(jiǎn)單單保存負(fù)數(shù),通過(guò)圖4我們知道,兩個(gè)數(shù)的補(bǔ)碼相加,可以得到一個(gè)準(zhǔn)確的數(shù)值。

再舉個(gè)相加結(jié)果為負(fù)數(shù)的例子,讓兩個(gè)負(fù)數(shù)相加:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖5

如果結(jié)果為負(fù)數(shù)的話,也是適用的,只是它仍然是以補(bǔ)碼的形式存放的,需要轉(zhuǎn)成原碼才符合我們?nèi)说睦斫夥绞健?/p>

現(xiàn)在回到上面留下的問(wèn)題,為什么byte的取值范圍是-128~127呢?

我們之前按照?qǐng)D1里的理解,理所應(yīng)當(dāng)?shù)囊詾樗鼞?yīng)該是-127~127的范圍,那是因?yàn)槲覀儼凑請(qǐng)D1的理解方式,數(shù)值就是以符號(hào)位+數(shù)值位的方式理解的(也就是按照原碼的方式理解的),但是你可以想一下,如果按照?qǐng)D1那種理解方式,是不是會(huì)存在兩個(gè)0值呢?

即:10000000和00000000,+0和-0;

其次如果站在機(jī)器角度上來(lái)說(shuō),所有的負(fù)數(shù)都很大,至少要比所有正數(shù)大,因?yàn)樨?fù)數(shù)的最高位也就是符號(hào)位都是1,顯然這是不對(duì)的,通過(guò)本節(jié)我們知道了,所有的數(shù)均通過(guò)自己的補(bǔ)碼完成計(jì)算,如果將最后得到的結(jié)果轉(zhuǎn)成原碼,就是我們?nèi)搜劭梢岳斫獾淖罱K值(符號(hào)位+數(shù)值位),如果現(xiàn)在利用補(bǔ)碼的方式做理解,符號(hào)位為0的數(shù)沒(méi)啥好說(shuō)的,自然取值區(qū)間為:0~127,但是符號(hào)位為1的負(fù)數(shù)呢?負(fù)數(shù)就存在一個(gè)特殊值(也就是我們之前片面理解的-0):10000000,如果按照原碼理解它是-0,但我們前面說(shuō)過(guò),計(jì)算機(jī)里所有數(shù)字,都是以補(bǔ)碼的方式參與運(yùn)算的,而負(fù)數(shù)的補(bǔ)碼不等于其原碼,這個(gè)10000000在計(jì)算機(jī)里顯然是某個(gè)負(fù)數(shù)的補(bǔ)碼,那么問(wèn)題就變的簡(jiǎn)單多了,即10000000是誰(shuí)的補(bǔ)碼呢?答案是:-128,這也是為什么負(fù)數(shù)的取值范圍會(huì)比正數(shù)多一個(gè)的原因,byte類(lèi)型如此,其它類(lèi)型也是如此,比如int型的負(fù)數(shù)取值也比正數(shù)多1。

這一塊的定義要清晰,對(duì)理解后面的位運(yùn)算會(huì)有很大的幫助。

二、java中的位運(yùn)算 2.1:與運(yùn)算

與運(yùn)算符號(hào):&

與運(yùn)算特點(diǎn):1&1=1、1&0=0、0&1=0、0&0=0

現(xiàn)在我們來(lái)舉一個(gè)例子:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖6

讓我們?cè)賮?lái)試試負(fù)數(shù):

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖7

2.2:或、異或

跟與運(yùn)算的運(yùn)算方式一致,只不過(guò)規(guī)則不太一樣:

或運(yùn)算符號(hào):|

或運(yùn)算規(guī)則:1|1=1、1|0=1、0|1=1、0|0=0

異或運(yùn)算符號(hào):^

異或運(yùn)算規(guī)則:1^1=0、1^0=1、0^1=1、0^0=0

2.3:按位取反

取反符號(hào):~

即一個(gè)數(shù)對(duì)自己取反,例如:

某個(gè)數(shù)字a的二進(jìn)制為: 1010110

                  則~a為: 0101001

2.4:左移運(yùn)算

左移運(yùn)算符:<<

例如:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖8

位運(yùn)算越界&數(shù)位拋棄:

圖8中的116的二進(jìn)制數(shù)的數(shù)值位為7位,符號(hào)位為0,此時(shí)如果左移超過(guò)24位,就會(huì)出現(xiàn)負(fù)數(shù),為什么會(huì)這樣?因?yàn)閖ava中的位移越界時(shí),java會(huì)拋棄高位越界部分,我們知道java里int類(lèi)型的第一位是符號(hào)位,如果符號(hào)位是1,則表示其為負(fù)數(shù),現(xiàn)在將數(shù)值位占7bit符號(hào)位為0的116左移24位,就會(huì)出現(xiàn)下方結(jié)果:

01110100000000000000000000000000

正好31位占全,頂至符號(hào)位,低位補(bǔ)0,我們稱(chēng)24為116的不越界的最大左移值,若超出這個(gè)值,就會(huì)越界,比如左移25位:

11101000000000000000000000000000

顯然左移25位后會(huì)把數(shù)值位的1移動(dòng)到符號(hào)位,這時(shí)它表示為一個(gè)負(fù)數(shù)的補(bǔ)碼。根據(jù)這個(gè)規(guī)則,我們?nèi)绻屍渥笠?8位,則值為:

01000000000000000000000000000000

也就是十進(jìn)制的1073741824,即:116 << 28 = 1073741824,那如果越界過(guò)多呢?比如int型的數(shù)據(jù),左移32位:116 << 32 = 116

會(huì)發(fā)現(xiàn),如果左移自己位數(shù)一樣多的位數(shù),那么這個(gè)數(shù)就等于它本身,因此運(yùn)算符合以下規(guī)則:

設(shè)x為被位移值,y為本次位移的位數(shù),z為x所屬類(lèi)型的最大存儲(chǔ)位數(shù):

x << y = x << (y%z)

如果是int型(32位,long型就用64代入計(jì)算),符合如下規(guī)則:

116 << 4 = 116 << (4%32) = 116 << 4 = 1856

116 << 32 = 116 << (32%32) = 116 << 0 = 116

116 << 36 = 116 << (36%32) = 116 << 4 = 1856

2.5:有符號(hào)右移運(yùn)算&無(wú)符號(hào)右移運(yùn)算

有符號(hào)右移運(yùn)算符:>>

無(wú)符號(hào)右移運(yùn)算符:>>>

例如:a >> b表示a右移b位,跟上面的左移例子一樣,右移也會(huì)有越界問(wèn)題,只是右移越界是從右邊開(kāi)始拋棄越界部分的,右移操作有符號(hào)位干擾,如果是正數(shù)右移,無(wú)此干擾項(xiàng),因?yàn)榉?hào)位本就是0右移不會(huì)影響值的準(zhǔn)確性,但如果是負(fù)數(shù),第一位是符號(hào)位,且值為1,右移就有影響了,現(xiàn)在仍然以116為例:

正數(shù)右移:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖9

上述是正數(shù),右移無(wú)影響,但是負(fù)數(shù),這里以-116為例,我們知道負(fù)數(shù)在計(jì)算機(jī)里是以補(bǔ)碼的形式存儲(chǔ)的,所以圖里直接用-116的補(bǔ)碼做運(yùn)算,位移過(guò)程如下:

 JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖10

你會(huì)發(fā)現(xiàn)右移跟左移不一樣,左移是不用擔(dān)心自己符號(hào)位存在“補(bǔ)位”問(wèn)題的,但是右移存在,如圖中-116右移4位后,左邊第一位,也就是符號(hào)位,就面臨著補(bǔ)位的問(wèn)題,那我現(xiàn)在是該補(bǔ)1呢,還是補(bǔ)0呢?這也就是為什么右移操作會(huì)存在有符號(hào)右移和無(wú)符號(hào)右移兩種移動(dòng)方式:

?? 有符號(hào)右移:依照原符號(hào)位,如果原符號(hào)位是1,那么圖4里需要補(bǔ)位的空位全部補(bǔ)1,如果原符號(hào)位為0,則全部補(bǔ)0

?? 無(wú)符號(hào)右移:無(wú)視原符號(hào)位,全部補(bǔ)0

現(xiàn)在讓我們用有符號(hào)的方式將-116右移4位,即-116 >> 4,按照有符號(hào)的規(guī)則,補(bǔ)位符合原符號(hào)位,則右邊4位全部補(bǔ)1:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖11

得到的仍然是個(gè)負(fù)數(shù),它仍然是一個(gè)補(bǔ)碼,圖里展示不開(kāi),它的結(jié)果為:11111111111111111111111111111000,經(jīng)轉(zhuǎn)換可知它是-8的補(bǔ)碼,即:-116 >> 4 = -8

現(xiàn)在再試試用無(wú)符號(hào)右移,根據(jù)無(wú)符號(hào)的特點(diǎn),右移后的前四位無(wú)腦補(bǔ)0:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖12

圖里展示不開(kāi),它的結(jié)果為:00001111111111111111111111111000

可見(jiàn)它是個(gè)正數(shù),轉(zhuǎn)換成十進(jìn)制為:268435448,即:-116 >>> 4 = 268435448

最后說(shuō)一下,跟左移一樣,右移里不管是有符號(hào)還是無(wú)符號(hào),也符合取余的方式,計(jì)算出位移的最終位數(shù):

-116 >> 4 = -116 >> (4%32) = -116 >> 4 = -8

-116 >> 32 = -116 >> (32%32) = -116 >> 0 = -116

-116 >> 36 = -116 >> (36%32) = -116 >> 4 = -8

2.6:類(lèi)型轉(zhuǎn)換溢出

了解完位運(yùn)算,來(lái)看一個(gè)比較實(shí)際的問(wèn)題,看下面的代碼:

long a = 8934567890233345621L;
int b = (int) a; //b的值為-1493678507

最終b的值是一個(gè)負(fù)數(shù),這是由于long型64位,讓int型強(qiáng)行接收,會(huì)出現(xiàn)位溢出的問(wèn)題,這個(gè)流程如下:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖13

三、位運(yùn)算在實(shí)際項(xiàng)目中的運(yùn)用

位運(yùn)算的性能是非常好的,相比運(yùn)算流程,計(jì)算機(jī)更喜歡這種純粹的邏輯門(mén)和移動(dòng)位置的運(yùn)算,但位運(yùn)算在平常的業(yè)務(wù)代碼里并不太常見(jiàn),因?yàn)樗目勺x性不太好,但是我們?nèi)匀豢梢岳梦贿\(yùn)算來(lái)解決一些實(shí)際項(xiàng)目里的問(wèn)題。

比如用來(lái)表示開(kāi)關(guān)的功能,比如需求里經(jīng)常有這種字段:是否允許xx(0不允許,1允許),是否有yy權(quán)限(0沒(méi)有,1有),是否存在zz(0不存在,1存在)

上面只是舉例,類(lèi)似這種只有兩種取值狀態(tài)的屬性,如果當(dāng)成數(shù)據(jù)庫(kù)字段放進(jìn)去的話,太過(guò)浪費(fèi),如果之后又有類(lèi)似的字段,又得新增數(shù)據(jù)庫(kù)字段,為了只有兩種取值的字段,實(shí)在是不太值得。

這個(gè)時(shí)候何不用一個(gè)字段來(lái)表示這些字段呢?你可能已經(jīng)猜到要怎么做了:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖14

頂一個(gè)int型或者long型的字段,讓它的每一個(gè)二進(jìn)制位擁有特殊含義即可,然后按照位運(yùn)算將其對(duì)應(yīng)的位置上的數(shù)值變成0或1,那如何將某個(gè)數(shù)的二進(jìn)制位第x位上的數(shù)值變成1或0呢?其實(shí)這在位圖結(jié)構(gòu)里經(jīng)常用到,就是利用1這個(gè)特殊的值作位移運(yùn)算后再與原值進(jìn)行位運(yùn)算,讓我們看下這個(gè)過(guò)程:

把一個(gè)數(shù)的第2位的字符變成1,現(xiàn)在假設(shè)這個(gè)數(shù)初始化為0,int型,我們把它當(dāng)成二進(jìn)制展示出來(lái):

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖15

現(xiàn)在如何把這個(gè)數(shù)的第二位變成1呢?目前是這樣做的:

0 | 1 << 1

即原值跟1左移1位后的值作或運(yùn)算,先來(lái)看看1 << 1的結(jié)果:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖16

然后拿著圖16的結(jié)果,跟原數(shù)(也就是0)進(jìn)行或運(yùn)算:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖17

可以看到,原數(shù)的第二位已經(jīng)被置為1了,它的十進(jìn)制對(duì)應(yīng)2,其它位的數(shù)置為1也大同小異,例如,現(xiàn)在讓第6位也變成1只需要:

2 | 1 << 5

即拿著原值(現(xiàn)在為2)跟1左移5位后的數(shù)做或運(yùn)算,這個(gè)流程如下:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖18

看完了把某個(gè)位置的數(shù)值置為1,那如何把某位設(shè)置為0呢?我們現(xiàn)在把圖18里的結(jié)果的第6位重新置回0,目前的做法為:

34 & ~(1 << 5)

即拿著原值(經(jīng)過(guò)上面幾步的運(yùn)算,現(xiàn)在值為32)跟1左移5位按位取反后的數(shù)做與運(yùn)算,來(lái)看下這個(gè)流程:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

圖19

經(jīng)過(guò)上面的流程,就可以把原值的第6位變成0了。

那么我們知道了讓一個(gè)數(shù)的二進(jìn)制位的某位變成0或1的方法,那如何知道一個(gè)數(shù)的某位上究竟是0還是1呢?畢竟我們業(yè)務(wù)代碼需要知道第幾位代表什么意思并且獲取到對(duì)應(yīng)位置上的值。

假如我現(xiàn)在想知道十進(jìn)制int型數(shù)34的第6位是0還是1,寫(xiě)法如下:

34 >> 5 & 1

即讓原值(34)右移5位后跟1做與運(yùn)算,來(lái)看下這個(gè)流程:

JAVA中如何實(shí)現(xiàn)位運(yùn)算

關(guān)于JAVA中如何實(shí)現(xiàn)位運(yùn)算就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。


標(biāo)題名稱(chēng):JAVA中如何實(shí)現(xiàn)位運(yùn)算
文章鏈接:http://weahome.cn/article/jhsgis.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部