java??常見(jiàn)位邏輯運(yùn)算符梳理
概述
最近在看jdk一些集合的框架的時(shí)候,頻繁出現(xiàn)位運(yùn)算,比如下圖,這對(duì)我閱讀源碼產(chǎn)生了很大的阻礙,因?yàn)槲覍?duì)這塊內(nèi)容也是一知半解,因?yàn)楹苌儆眠^(guò),即便學(xué)過(guò)基本也還給老師了,這篇文章主要針對(duì)java中的位運(yùn)算做一個(gè)總結(jié)。
位運(yùn)算符介紹
在Java語(yǔ)言中,提供了7種位運(yùn)算符,分別是按位與(&)、按位或(|)、按位異或(^)、取反(~)、左移(<<)、帶符號(hào)右移(>>)和無(wú)符號(hào)右移(>>>)。位運(yùn)算符是對(duì)long、int、short、byte和char這5種類(lèi)型的數(shù)據(jù)進(jìn)行運(yùn)算的,我們不能對(duì)double、float和boolean進(jìn)行位運(yùn)算操作。
位運(yùn)算符只要是正對(duì)二進(jìn)制的數(shù)據(jù)進(jìn)行操作,由于java中最終是按照補(bǔ)碼的方式存儲(chǔ)的,至于為什么按照補(bǔ)碼的方式,是另外一個(gè)話題了,按下不表。
正數(shù)的原碼和反碼、補(bǔ)碼一樣。負(fù)數(shù)的反碼:把原碼的符號(hào)位保持不變,數(shù)值位逐位取反,即可得原碼的反碼。負(fù)數(shù)的補(bǔ)碼:在反碼的基礎(chǔ)上加 1 即得該原碼的補(bǔ)碼。
位邏輯運(yùn)算符
位邏輯運(yùn)算符有以下4種,按位與(&)、按位或(|)、按位異或(^)、取反(~)。
位與(&)運(yùn)算符
位與運(yùn)算符為&,運(yùn)算規(guī)則是:參與運(yùn)算的數(shù)字,低位對(duì)齊,高位不足的補(bǔ)零,如果對(duì)應(yīng)的二進(jìn)制位同時(shí)為 1,那么計(jì)算結(jié)果才為 1,否則為 0。因此,任何數(shù)與 0 進(jìn)行按位與運(yùn)算,其結(jié)果都為 0,最左邊的符號(hào)位也是要參與運(yùn)算的。
例子: 5&6
首先把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é)果。
通過(guò)位與運(yùn)算符特點(diǎn)推導(dǎo)出如下結(jié)論:
- 任何數(shù)與 0 進(jìn)行按位與運(yùn)算,其結(jié)果都為 0
位或(|)運(yùn)算符
位或運(yùn)算符為|,其運(yùn)算規(guī)則是:參與運(yùn)算的數(shù)字,低位對(duì)齊,高位不足的補(bǔ)零。如果對(duì)應(yīng)的二進(jìn)制位只要有一個(gè)為 1,那么結(jié)果就為 1;如果對(duì)應(yīng)的二進(jìn)制位都為 0,結(jié)果才為 0。
例子: 5|6
首先還是把這兩個(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。
通過(guò)位或運(yùn)算符特點(diǎn)推導(dǎo)出如下結(jié)論:
- 任何數(shù)與 0 進(jìn)行按位或運(yùn)算,其結(jié)果都是它本身
- 任何數(shù)與 位數(shù)都是1的二進(jìn)制進(jìn)行按位或運(yùn)算,其結(jié)果的二進(jìn)制位數(shù)都是1
位異或(^)運(yùn)算符
位異或運(yùn)算符為^,其運(yùn)算規(guī)則是:參與運(yùn)算的數(shù)字,低位對(duì)齊,高位不足的補(bǔ)零,如果對(duì)應(yīng)的二進(jìn)制位相同(同時(shí)為 0 或同時(shí)為 1)時(shí),結(jié)果為 0;如果對(duì)應(yīng)的二進(jìn)制位不相同,結(jié)果則為 1。
例子: 5^6
同樣是先轉(zhuǎn)成補(bǔ)碼,然后異或計(jì)算,得到最后的二進(jìn)制結(jié)果11,轉(zhuǎn)成十進(jìn)制為3。
通過(guò)異或運(yùn)算符特點(diǎn)推導(dǎo)出如下結(jié)論:
- 異或運(yùn)算符滿足交換律,a^b與b^a是等價(jià)的。
- 任何兩個(gè)相同的數(shù)字進(jìn)行異或操作,所得到的結(jié)果都必然為0。
- 對(duì)于任意一個(gè)二進(jìn)制位來(lái)說(shuō),這個(gè)位上的數(shù)與0進(jìn)行異或運(yùn)算,運(yùn)算結(jié)果與這個(gè)二進(jìn)制位上的數(shù)是相同的,而與1進(jìn)行異或運(yùn)算,結(jié)果與這個(gè)二進(jìn)制位上的數(shù)字相反。
- 對(duì)于任何兩個(gè)整數(shù)a和b,a^b^b等于a, 對(duì)于任何兩個(gè)整數(shù)a和b,a^b^a等于b
位取反(~)運(yùn)算符
位取反運(yùn)算符為~,其運(yùn)算規(guī)則是:只對(duì)一個(gè)操作數(shù)進(jìn)行運(yùn)算,將操作數(shù)二進(jìn)制中的 1 改為 0,0 改為 1。
例子:對(duì)數(shù)字5取反
首先把數(shù)字5轉(zhuǎn)換成補(bǔ)碼形式,之后把每個(gè)二進(jìn)制位上的數(shù)字進(jìn)行取反,如果是0就變成1,如果1就變成0,經(jīng)過(guò)取反后得到的二進(jìn)制串就是運(yùn)算結(jié)果,此時(shí)是補(bǔ)碼的形式,需要轉(zhuǎn)回原碼,符號(hào)位為1,其余各位取反,然后再整個(gè)數(shù)加1, 這個(gè)運(yùn)算結(jié)果被還原為十進(jìn)制數(shù)是-6。
注意:位運(yùn)算符的操作數(shù)只能是整型或者字符型數(shù)據(jù)以及它們的變體,不用于 float、double 或者 long 等復(fù)雜的數(shù)據(jù)類(lèi)型。
位移位運(yùn)算符
位移相關(guān)的運(yùn)算符有三個(gè),分別是左移(<<)、帶符號(hào)右移(>>)、無(wú)符號(hào)右移(>>>)。
左移運(yùn)算符
左移位運(yùn)算符為<<,其運(yùn)算規(guī)則是:按二進(jìn)制形式把所有的數(shù)字向左移動(dòng)對(duì)應(yīng)的位數(shù),高位移出(舍棄),低位的空位補(bǔ)零。
根據(jù)左移運(yùn)算符可以推導(dǎo)出:
- 左移運(yùn)算有乘以2的N次方的效果。一個(gè)數(shù)向左移動(dòng)1位,就相當(dāng)于乘以2的1次方,移動(dòng)兩位就相當(dāng)于乘以2的2次方,也就是乘以4。
帶符號(hào)右移運(yùn)算符
右位移運(yùn)算符為>>,其運(yùn)算規(guī)則是:符號(hào)位不變,按二進(jìn)制形式把所有的數(shù)字向右移動(dòng)對(duì)應(yīng)的位數(shù),低位移出(舍棄),高位的空位補(bǔ)零。
根據(jù)帶符號(hào)右移運(yùn)算符特點(diǎn)可以推導(dǎo)出:
- 對(duì)于正數(shù)而言,帶符號(hào)右移之后產(chǎn)生的數(shù)字確實(shí)等于除以2的N次方。
- 對(duì)于任何一個(gè)byte、short或者int類(lèi)型的數(shù)據(jù)而言,帶符號(hào)右移31位之后,得到的必然是0或者是-1。對(duì)于long類(lèi)型的數(shù)據(jù)而言,帶符號(hào)右移63位之后,得到的也必然是0或者是-1。
無(wú)符號(hào)右移
無(wú)符號(hào)右移運(yùn)算符為>>>, 其運(yùn)算規(guī)則是:無(wú)符號(hào)右移在二進(jìn)制串移動(dòng)之后,空位由0來(lái)補(bǔ)充,與符號(hào)位是0還是1毫無(wú)關(guān)系,注意這里的無(wú)符號(hào)是忽略符號(hào)位,也參與移位。
常見(jiàn)的位運(yùn)算
- 計(jì)算m*2^n
System.out.println("2^3=" + (1 << 3));// 2^3=8 System.out.println("3*2^3=" + (3 << 3));// 3*2^3=24 System.out.println("5*2^3=" + (5 << 3));// 5*2^3=40
- 判斷一個(gè)數(shù)n的奇偶性
System.out.println((5 & 1) == 1 ? "奇數(shù)" : "偶數(shù)"); // 奇數(shù) System.out.println((6 & 1) == 1 ? "奇數(shù)" : "偶數(shù)"); // 偶數(shù) System.out.println((0 & 1) == 1 ? "奇數(shù)" : "偶數(shù)"); // 偶數(shù) System.out.println((-1 & 1) == 1 ? "奇數(shù)" : "偶數(shù)"); // 奇數(shù) System.out.println((-2 & 1) == 1 ? "奇數(shù)" : "偶數(shù)"); // 偶數(shù)
- 取絕對(duì)值
System.out.println((-5 ^ (-5 >> 31)) - (-5 >> 31));// 5 System.out.println((0 ^ (0 >> 31)) - (0 >> 31));// 0
4個(gè)字節(jié) 32位,a>>31取得a的符號(hào);
任何正數(shù)右移31后只剩符號(hào)位0,溢出的31位截?cái)?,空出?1位補(bǔ)符號(hào)位0,最終結(jié)果為0;
任何負(fù)數(shù)右移31后只剩符號(hào)位1,溢出的31位截?cái)?,空出?1位補(bǔ)符號(hào)位1,最終結(jié)果為 -1;
正數(shù) ^ 0 = 正數(shù)本身(二進(jìn)制不變);
負(fù)數(shù) ^ -1 = 它的絕對(duì)值 -1(二進(jìn)制翻轉(zhuǎn)每一位);
總結(jié)
位運(yùn)算符這塊個(gè)人覺(jué)得還是挺復(fù)雜的,還是需要不斷的加深學(xué)習(xí)和理解。這里強(qiáng)調(diào)一點(diǎn),位運(yùn)算計(jì)算后,不會(huì)影響值得本身,比如 int a=5; ~a; 這個(gè)a本身并沒(méi)有改變。另一方面,位運(yùn)算的效率是遠(yuǎn)遠(yuǎn)大于直接計(jì)算的。
到此這篇關(guān)于java 位邏輯運(yùn)算符詳細(xì)解說(shuō)的文章就介紹到這了,更多相關(guān)java 位邏輯運(yùn)算符內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決在for循環(huán)中remove list報(bào)錯(cuò)越界的問(wèn)題
這篇文章主要介紹了解決在for循環(huán)中remove list報(bào)錯(cuò)越界的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12Springboot整合Dubbo教程之項(xiàng)目創(chuàng)建和環(huán)境搭建
本篇文章主要介紹了Springboot整合Dubbo教程之項(xiàng)目創(chuàng)建和環(huán)境搭建,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12java中重寫(xiě)父類(lèi)方法加不加@Override詳解
這篇文章主要介紹了java中重寫(xiě)父類(lèi)方法加不加@Override詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06MyBatis 如何簡(jiǎn)化的 JDBC(思路詳解)
MyBatis 是一個(gè) 持久層 框架,用于 簡(jiǎn)化JDBC開(kāi)發(fā),這篇文章主要介紹了MyBatis 如何簡(jiǎn)化的 JDBC(思路詳解),需要的朋友可以參考下2023-03-03Java中JDBC連接池的基本原理及實(shí)現(xiàn)方式
本文詳細(xì)講解了Java中JDBC連接池的基本原理及實(shí)現(xiàn)方式,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12重新認(rèn)識(shí)Java中的ThreadLocal
ThreadLocal是JDK包提供的,它提供線程本地變量,如果創(chuàng)建一個(gè)ThreadLocal變量,那么訪問(wèn)這個(gè)變量的每個(gè)線程都會(huì)有這個(gè)變量的一個(gè)副本,在實(shí)際多線程操作的時(shí)候,操作的是自己本地內(nèi)存中的變量,從而規(guī)避了線程安全問(wèn)題2021-05-05springboot springmvc拋出全局異常的解決方法
這篇文章主要為大家詳細(xì)介紹了springboot springmvc拋出全局異常的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06bootstrap實(shí)現(xiàn)多個(gè)下拉框同時(shí)搜索的實(shí)例
下面小編就為大家?guī)?lái)一篇bootstrap實(shí)現(xiàn)多個(gè)下拉框同時(shí)搜索的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07