溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java中7種位運(yùn)算符的使用方法

發(fā)布時(shí)間:2020-05-29 21:09:10 來源:億速云 閱讀:1498 作者:鴿子 欄目:編程語言

很多編程語言都有位運(yùn)算符,Java語言也不例外。在Java語言中,提供了7種位運(yùn)算符,分別是按位與(&)、按位或(|)、按位異或(^)、取反(~)、左移(<<)、帶符號(hào)右移(>>)和無符號(hào)右移(>>>)。這些運(yùn)算符當(dāng)中,僅有~是單目運(yùn)算符,其他運(yùn)算符均為雙目運(yùn)算符。在講解這些運(yùn)算符的使用之前,必須了解一個(gè)常識(shí),那就是:位運(yùn)算符是對(duì)long、int、short、byte和char這5種類型的數(shù)據(jù)進(jìn)行運(yùn)算的,我們不能對(duì)double、float和boolean進(jìn)行位運(yùn)算操作。下面就來詳細(xì)講解這7種位運(yùn)算符的使用方法。

一、按位與運(yùn)算符

按位與運(yùn)算符的寫法是一個(gè)”&”符號(hào),與”不短路的邏輯與運(yùn)算符”寫法是完全一樣的,但意義不同。邏輯與運(yùn)算是對(duì)布爾型數(shù)據(jù)進(jìn)行運(yùn)算,而按位與運(yùn)算是對(duì)二進(jìn)制位上的數(shù)值進(jìn)行計(jì)算。按位與運(yùn)算符的運(yùn)算規(guī)則如下圖所示:
Java中7種位運(yùn)算符的使用方法
運(yùn)算規(guī)則總結(jié)成一句話就是:如果兩個(gè)二進(jìn)制位上的數(shù)都是1,那么運(yùn)算結(jié)果為1,其他情況運(yùn)算結(jié)果均為0。下面舉例說明按位與運(yùn)算符的運(yùn)算過程,我們用數(shù)字5和6進(jìn)行按位與運(yùn)算。這個(gè)過程可以用下圖表示:
Java中7種位運(yùn)算符的使用方法
運(yùn)算過程中,首先把5和6這兩個(gè)數(shù)字轉(zhuǎn)換為補(bǔ)碼,之后還要把這兩個(gè)數(shù)字按位對(duì)齊,然后一一把兩個(gè)相應(yīng)的二進(jìn)制位上的數(shù)字進(jìn)行按位與運(yùn)算,運(yùn)算得到的二進(jìn)制串就是最終的結(jié)果。按照補(bǔ)碼反向轉(zhuǎn)換為十進(jìn)制數(shù)字的規(guī)則,可以計(jì)算出5&6的運(yùn)算結(jié)果是4。在這里要提醒大家一句:進(jìn)行位運(yùn)算的時(shí)候,最左邊的符號(hào)位也是要參與運(yùn)算的。

二、按位或運(yùn)算符

按位或運(yùn)算符的寫法是一個(gè)”|”符號(hào),與”不短路的邏輯或運(yùn)算符”寫法相同,它的運(yùn)算規(guī)則也很簡(jiǎn)單,如下圖所示:

Java中7種位運(yùn)算符的使用方法
運(yùn)算規(guī)則概括成比較好記的一句話就是:兩個(gè)二進(jìn)制位上的數(shù)字如果都為0,那么運(yùn)算結(jié)果為0,否則運(yùn)算結(jié)果是1。同按位與運(yùn)算一樣,符號(hào)位也要參與運(yùn)算。下面我們還是用5和6為例來講解一下按位或的運(yùn)算過程,如下圖所示:

Java中7種位運(yùn)算符的使用方法
首先還是把這兩個(gè)數(shù)字轉(zhuǎn)換成補(bǔ)碼形式,之后把相應(yīng)的二進(jìn)制位上的數(shù)字進(jìn)行按位或運(yùn)算:如果兩個(gè)二進(jìn)制數(shù)都是0,計(jì)算結(jié)果為0,其他情況計(jì)算結(jié)果均為1。按照這個(gè)規(guī)則把每一位上的數(shù)字都計(jì)算一遍后,得到二進(jìn)制的運(yùn)算結(jié)果是111,這個(gè)運(yùn)算結(jié)果轉(zhuǎn)換為十進(jìn)制數(shù)是7。

三、按位異或運(yùn)算符

按位異或運(yùn)算符寫法是”^”,它的運(yùn)算規(guī)則如下圖:

Java中7種位運(yùn)算符的使用方法
如上圖,運(yùn)算規(guī)則為:兩個(gè)二進(jìn)制位上的數(shù)字如果相同,則運(yùn)算結(jié)果為0,如果兩個(gè)二進(jìn)制位上的數(shù)字不相同,則運(yùn)算結(jié)果為1。下面我們還是用5和6為例來講解一下異或的運(yùn)算過程,如下圖:
Java中7種位運(yùn)算符的使用方法
首先還是把這兩個(gè)數(shù)字轉(zhuǎn)換成補(bǔ)碼形式,之后把相應(yīng)的二進(jìn)制位上的數(shù)字進(jìn)行異或運(yùn)算,如果對(duì)應(yīng)的兩個(gè)二進(jìn)制位上的數(shù)相同,計(jì)算結(jié)果為0,否則計(jì)算結(jié)果為1。按照這個(gè)規(guī)則把每一位上的數(shù)字都計(jì)算一遍后,得到二進(jìn)制的運(yùn)算結(jié)果是11,這個(gè)運(yùn)算結(jié)果轉(zhuǎn)換為十進(jìn)制數(shù)是3。
關(guān)于異或運(yùn)算符,有很多非常有用的特性,我們?cè)谶@里梳理總結(jié)一下。
Ⅰ、異或運(yùn)算符滿足交換律
也就是說,a^b與b^a是等價(jià)的,雖然a和b交換了位置,但還是會(huì)運(yùn)算出相同的結(jié)果。這個(gè)規(guī)律還可以推廣到N個(gè)操作數(shù),也就是說,如果有N個(gè)變量都參與了異或運(yùn)算,那么它們的位置無論如何交換,運(yùn)算的結(jié)果都是相同的。

Ⅱ、任何兩個(gè)相同的數(shù)字進(jìn)行異或操作,所得到的結(jié)果都必然為0
這個(gè)特性并不難理解,因?yàn)閮蓚€(gè)相同的數(shù)字,換算成補(bǔ)碼后,每個(gè)二進(jìn)制位上的數(shù)也都相同,這樣在進(jìn)行異或運(yùn)算時(shí),按照運(yùn)算規(guī)則,每個(gè)二進(jìn)制位上得到的運(yùn)算結(jié)果也都是0,這N個(gè)0所組成的二進(jìn)制串就是數(shù)字0的補(bǔ)碼。我們可以利用這個(gè)特性快速的判斷兩個(gè)整數(shù)是否相同。另外,利用這個(gè)特性還可以實(shí)現(xiàn)內(nèi)存的快速清零操作,比如我們可以在代碼中寫上a=a^a;這條語句能快速的把變量a所占據(jù)的那幾個(gè)字節(jié)的內(nèi)存迅速清零。

Ⅲ、對(duì)于任意一個(gè)二進(jìn)制位來說,這個(gè)位上的數(shù)與0進(jìn)行異或運(yùn)算,運(yùn)算結(jié)果與這個(gè)二進(jìn)制位上的數(shù)是相同的,而與1進(jìn)行異或運(yùn)算,結(jié)果與這個(gè)二進(jìn)制位上的數(shù)字相反
注意,我們現(xiàn)在說的是二進(jìn)制位上的數(shù)字,所謂相反不是說原來這個(gè)位上是1,運(yùn)算結(jié)果是-1,而是說原來是1,運(yùn)算結(jié)果為0,原來如果是0,運(yùn)算結(jié)果是1,這才是此處所說的”相反”的概念。這個(gè)特性也非常好理解,小伙伴們一定要記住它,在以后進(jìn)行一些位運(yùn)算操作的時(shí)候經(jīng)常會(huì)用到這個(gè)特性。

Ⅳ、對(duì)于任何兩個(gè)整數(shù)a和b,a^b^b等于a

這個(gè)結(jié)論為什么成立呢?簡(jiǎn)單說來,就是因?yàn)檫@個(gè)表達(dá)式中有b^b,而b^b的結(jié)果為0,前文已講過,任何一個(gè)數(shù)與0進(jìn)行按位異或操作,結(jié)果仍然是這個(gè)數(shù)本身,所以,a^b^b等于a。這個(gè)特性在加密運(yùn)算方面有著很普遍的應(yīng)用。我們可以把a(bǔ)當(dāng)作要加密的數(shù)據(jù),而把b當(dāng)作密鑰。a異或b就是把a(bǔ)用密鑰b進(jìn)行了加密操作,當(dāng)需要解密時(shí),仍然以b作為密鑰,再進(jìn)行一次異或就實(shí)現(xiàn)了解密。
這個(gè)特性還可以推出另外一個(gè)結(jié)論:對(duì)于任何兩個(gè)整數(shù)a和b,a^b^a等于b。我們能夠得到這個(gè)結(jié)論的原因也很簡(jiǎn)單,就是因?yàn)榘凑战粨Q律,a^b與b^a的運(yùn)算結(jié)果是一樣的,所以a^b^a等價(jià)于b^a^a,這個(gè)表達(dá)式中出現(xiàn)了a^a,a^a的值也為0,所以整個(gè)表達(dá)式的其實(shí)就相當(dāng)于b^0,最終結(jié)果還是b。
希望大家能夠牢記以上這些結(jié)論,在后續(xù)的文章中,會(huì)講解如何用這些結(jié)論去解決實(shí)際問題。

四、按位取反運(yùn)算符

按位取反運(yùn)算符寫法是”~”,它的運(yùn)算規(guī)則是:對(duì)每個(gè)二進(jìn)制位進(jìn)行取反操作,所謂取反就是原來二進(jìn)制位上如果是0,那么就變成1,反之,如果原來二進(jìn)制位上是1,那么就變?yōu)?。取反運(yùn)算符是一個(gè)單目運(yùn)算符,所以只需要一個(gè)操作數(shù)就可以了。我們以數(shù)字5為例講解按位取反的運(yùn)算過程:
Java中7種位運(yùn)算符的使用方法
首先把數(shù)字5轉(zhuǎn)換成補(bǔ)碼形式,之后把每個(gè)二進(jìn)制位上的數(shù)字進(jìn)行取反,如果是0就變成1,如果1就變成0,經(jīng)過取反后得到的二進(jìn)制串就是運(yùn)算結(jié)果,這個(gè)運(yùn)算結(jié)果被還原為十進(jìn)制數(shù)是-6。取反運(yùn)算符的運(yùn)算規(guī)則也非常容易理解,但是在這里老師需要提醒各位讀者注意:如果是對(duì)變量進(jìn)行取反操作,那么經(jīng)過操作之后,變量的值并不會(huì)發(fā)生變化!為方便小伙伴們理解,請(qǐng)看下圖:
Java中7種位運(yùn)算符的使用方法
從程序運(yùn)行的結(jié)果可以看出:輸出a的值還是5,這說明變量a經(jīng)過取反得到的那個(gè)-6并沒有被賦值到變量a中,通過這個(gè)例子可以證明,取反運(yùn)算并沒有對(duì)變量重新賦值的功能,取反運(yùn)算的結(jié)果只是臨時(shí)保存在操作數(shù)棧中,變量本身的值不會(huì)因取反操作而發(fā)生改變。

下面再來講解一下與位移相關(guān)的運(yùn)算符。所謂”位移”就是指在內(nèi)存中對(duì)二進(jìn)制串進(jìn)行移動(dòng)的操作。只要是移動(dòng)操作,就必然會(huì)涉及到以下幾個(gè)問題,怎樣表示移動(dòng)方向?怎樣表示移動(dòng)的位數(shù)?移動(dòng)之后空出來的二進(jìn)制位用什么來填充?移動(dòng)之后跑到原來內(nèi)存單元外面的那些數(shù)字怎么處理?符號(hào)位要不要跟著一起移動(dòng)?這些問題都是我們學(xué)習(xí)位移操作要弄清楚的細(xì)節(jié)。各位小伙伴可以帶著這些問題來學(xué)習(xí)位移相關(guān)的運(yùn)算符。與位移相關(guān)的運(yùn)算符有三個(gè),分別是左移(<<)、帶符號(hào)右移(>>)、無符號(hào)右移(>>>)。

五、左移運(yùn)算符

左移運(yùn)算符的寫法是”<<“,看上去向兩個(gè)向左的箭頭,表示要把二進(jìn)制數(shù)據(jù)在內(nèi)存空間中向左邊移動(dòng)。使用左移運(yùn)算符時(shí),把想進(jìn)行位移操作的操作數(shù)放最左面,之后寫上左移運(yùn)算符,在左移運(yùn)算符的右邊寫上移動(dòng)的位數(shù)。例如:"5<<2"就表示對(duì)數(shù)字5進(jìn)行左移2位的操作。下圖展示了進(jìn)行左移操作之后,二進(jìn)制串在內(nèi)存中是怎樣變化的:
Java中7種位運(yùn)算符的使用方法
可以看到這個(gè)二進(jìn)制串在內(nèi)存中整體向左移動(dòng)了兩位,那么最左邊的兩位就跑到內(nèi)存單元的外面去了,這兩位數(shù)字將會(huì)被舍棄,右邊空出的兩位用0補(bǔ)齊。
左移運(yùn)算有乘以2的N次方的效果。一個(gè)數(shù)向左移動(dòng)1位,就相當(dāng)于乘以2的1次方,移動(dòng)兩位就相當(dāng)于乘以2的2次方,也就是乘以4。位移操作在實(shí)際運(yùn)算時(shí)遠(yuǎn)遠(yuǎn)快于乘法操作,所以在某些對(duì)運(yùn)算速度要求非常高的場(chǎng)合,可以考慮用左移代替乘以2的N次方的乘法操作。但是需要提醒大家注意三個(gè)細(xì)節(jié):
首先:位移操作同取反操作一樣,并不能改變變量本身的值,所能改變的僅是存儲(chǔ)在操作數(shù)棧中那個(gè)數(shù)據(jù)的值,不理解這句話意思的小伙伴看下圖:

Java中7種位運(yùn)算符的使用方法
其次:當(dāng)位移的位數(shù)很多時(shí),導(dǎo)致最左邊的符號(hào)位發(fā)生變化,就不再具有乘以2的N次方的效果了。比如十進(jìn)制的5轉(zhuǎn)換為補(bǔ)碼形式是:前面29個(gè)0最后3位是101,如果移動(dòng)29位,那么最前面的符號(hào)位就變成了1,此時(shí)運(yùn)算的結(jié)果就成為了一個(gè)負(fù)數(shù),不再是5乘以2的29次方的乘法結(jié)果。
最后:對(duì)于byte/short/int三種類型的數(shù)據(jù),Java語言最多支持31位的位移運(yùn)算,對(duì)于long類型的數(shù)據(jù)而言,最多支持63位的位移運(yùn)算。這可能是因?yàn)镴ava語言的設(shè)計(jì)者認(rèn)為位移的偏移量已經(jīng)超過存儲(chǔ)數(shù)據(jù)本身的長(zhǎng)度,沒有什么意義。小伙伴們可以試一下數(shù)字5左移32位是什么結(jié)果。

六、帶符號(hào)右移運(yùn)算符

右移運(yùn)算分為兩種,分別是帶符號(hào)右移和無符號(hào)右移。首先我們來說說帶符號(hào)右移運(yùn)算符。帶符號(hào)右移運(yùn)算符的寫法是”>>“,與左移運(yùn)算符的方向恰好相反。所謂帶符號(hào)右移就是指當(dāng)二進(jìn)制串向右邊移動(dòng)以后,左邊空出的位用”符號(hào)位上的數(shù)字”填充,說的更直白一點(diǎn),如果是正數(shù),二進(jìn)制串右移的時(shí)候用0來填充左邊的空位,而對(duì)于負(fù)數(shù)而言,右移的時(shí)候用1來填充左邊的空位,如下圖:

Java中7種位運(yùn)算符的使用方法
從圖上可以清楚的看到帶符號(hào)右移操作在二進(jìn)制串移動(dòng)之后左邊空位是怎樣被填充的。之前強(qiáng)調(diào)過,左移操作具有乘以2的N次方的效果,其實(shí)帶符號(hào)右移也具有”類似”除以2的N次方的效果。請(qǐng)注意,這里說的是”類似”除以2的N次方的效果,為什么要加上”類似”兩個(gè)字呢?就是因?yàn)閷?duì)于正數(shù)而言,帶符號(hào)右移之后產(chǎn)生的數(shù)字確實(shí)等于除以2的N次方,但是對(duì)于負(fù)數(shù)而言,帶符號(hào)右移是在除以2的N次方的結(jié)果之上還要減去1。比如對(duì)于正5,帶符號(hào)右移兩位的結(jié)果是1,而對(duì)于-5,帶符號(hào)右移兩位的結(jié)果是-2,也就是-5被2的2次方整除再減去1的結(jié)果。
帶符號(hào)右移的操作可以保證移動(dòng)之前和移動(dòng)之后數(shù)字的正負(fù)屬性不變,原來是正數(shù),不管移動(dòng)多少位,移動(dòng)之后還是正數(shù),原來是負(fù)數(shù),移動(dòng)之后還是負(fù)數(shù)。另外,我們還可以繼續(xù)深挖一下這個(gè)特性,從而得到一個(gè)結(jié)論:對(duì)于任何一個(gè)byte、short或者int類型的數(shù)據(jù)而言,帶符號(hào)右移31位之后,得到的必然是0或者是-1。對(duì)于long類型的數(shù)據(jù)而言,帶符號(hào)右移63位之后,得到的也必然是0或者是-1。能夠得出這個(gè)結(jié)論的依據(jù)也很簡(jiǎn)單,就是因?yàn)閷?duì)于byte、short和int類型的變量而言,如果是正數(shù),帶符號(hào)右移31位之后產(chǎn)生的二進(jìn)制串必然全部是0,轉(zhuǎn)換成對(duì)應(yīng)的十進(jìn)制數(shù)就是0;而對(duì)于負(fù)數(shù)而言,帶符號(hào)右移31位之后產(chǎn)生的二進(jìn)制串必然全部是1,轉(zhuǎn)換成十進(jìn)制數(shù)就是-1。對(duì)于long類型的數(shù)據(jù),帶符號(hào)右移63位也具有相同效果。

七、無符號(hào)右移運(yùn)算符

前文已說過:右移運(yùn)算分為兩種,分別是帶符號(hào)右移和無符號(hào)右移。現(xiàn)在再來講解無符號(hào)右移。無符號(hào)右移運(yùn)算符的寫法是”>>>”,比帶符號(hào)右移多了一個(gè)”>”。帶符號(hào)右移的運(yùn)算規(guī)則與無符號(hào)右移的運(yùn)算規(guī)則差別就在于:無符號(hào)右移在二進(jìn)制串移動(dòng)之后,空位由0來補(bǔ)充,與符號(hào)位是0還是1毫無關(guān)系,如下圖:
Java中7種位運(yùn)算符的使用方法
更多相關(guān)內(nèi)容:

java中有哪些運(yùn)算符

java運(yùn)算符優(yōu)先級(jí)是什么

以上圖片展示了無符號(hào)右移的運(yùn)算規(guī)則。對(duì)于正數(shù)而言,無符號(hào)右移和帶符號(hào)右移沒有什么區(qū)別,而對(duì)于負(fù)數(shù)而言,經(jīng)過無符號(hào)右移會(huì)產(chǎn)生一個(gè)正數(shù),因?yàn)樽钭筮叺姆?hào)位被0填充了。

向AI問一下細(xì)節(jié)

免責(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)容。

AI