java 移位運(yùn)算符

最近工作中被運(yùn)算效率問(wèn)題所困擾,比如大數(shù)據(jù)排序或者去重腌且,因此現(xiàn)在需要補(bǔ)習(xí)一下位移運(yùn)算元践。

首先講一下位移概念片酝?

左位移(<<):將運(yùn)算符左邊的對(duì)象向左移動(dòng)運(yùn)算符右邊指定的位數(shù)(在低位補(bǔ)0) eg:x<<3

右位移(>>):"有符號(hào)"右移運(yùn)算 符,將運(yùn)算符左邊的對(duì)象向右移動(dòng)運(yùn)算符右邊指定的位數(shù)。使用符號(hào)擴(kuò)展機(jī)制篓吁,也就是說(shuō)莉擒,如果值為正挠唆,則在高位補(bǔ)0婚脱,如果值為負(fù),則在高位補(bǔ)1. eg:x>>3

無(wú)符號(hào)右移位(>>>):"無(wú)符號(hào)"右移運(yùn)算 符重付,將運(yùn)算符左邊的對(duì)象向右移動(dòng)運(yùn)算符右邊指定的位數(shù)顷级。采用0擴(kuò)展機(jī)制,也就是說(shuō)确垫,無(wú)論值的正負(fù)弓颈,都在高位補(bǔ)0?x>>>3

以int類型的6297為例拣凹,代碼如下:

[java]view plaincopy

System.out.println(Integer.toBinaryString(6297));???

System.out.println(Integer.toBinaryString(-6297));???

System.out.println(Integer.toBinaryString(6297>>5));???

System.out.println(Integer.toBinaryString(-6297>>5));???

System.out.println(Integer.toBinaryString(6297>>>5));???

System.out.println(Integer.toBinaryString(-6297>>>5));???

System.out.println(Integer.toBinaryString(6297<<5));???

System.out.println(Integer.toBinaryString(-6297<<5));??


? 運(yùn)行結(jié)果:

1100010011001

11111111111111111110011101100111

11000100

11111111111111111111111100111011

11000100

111111111111111111100111011

110001001100100000

11111111111111001110110011100000

注:x<>y相當(dāng)于x/2y

??? 從計(jì)算速度上講,移位運(yùn)算要比算術(shù)運(yùn)算快恨豁。

??? 如果x是負(fù)數(shù)嚣镜,那么x>>>3沒(méi)有什么算術(shù)意義,只有邏輯意義橘蜜。


在Think inJava中有這么一段話

“對(duì)char菊匿,byte或者short進(jìn)行移位處理,那么在移位進(jìn)行之前计福,它們會(huì)自動(dòng)轉(zhuǎn)換成一個(gè)int跌捆。只有右側(cè)的5個(gè)低位才會(huì)有用。這樣可防止我們?cè)谝粋€(gè)int數(shù)里移動(dòng)不切實(shí)際的位數(shù)象颖。若對(duì)一個(gè)long值進(jìn)行處理佩厚,最后得到的結(jié)果也是long。此時(shí)只會(huì)用到右側(cè)的6個(gè)低位说订,防止移動(dòng)超過(guò)long值里現(xiàn)成的位數(shù)抄瓦。”


這段話有兩個(gè)出處陶冷,一個(gè)是Java編程思想3.11移位操作符中出現(xiàn)钙姊,原話是“只有數(shù)值右端的低5位才有用”。一個(gè)是Java解惑中謎題27:變幻莫測(cè)的i值埂伦,原話是“移位操作符只使用其右操作數(shù)的低5位作為移位長(zhǎng)度”煞额。

弄清這句話首先需要弄清楚移位操作符,移位操作符是一個(gè)二元操作符沾谜,兩個(gè)操作數(shù)分別位于移位操作兩邊形如:左操作數(shù)?移位操作符?右操作數(shù)?這樣的結(jié)構(gòu)膊毁,其含義是,將左操作數(shù)按照移位操作符指定的移位方向基跑,進(jìn)行右操作數(shù)指定的次數(shù)的移位婚温。然后對(duì)照出處二,Java解惑中所描述的涩僻,就豁然開朗了缭召。

首先,移位操作符能操作的數(shù)只有int類型和long類型逆日,這個(gè)是指左操作數(shù)的類型。對(duì)于int類型而言萄凤,int在Java中占4字節(jié)室抽,一共32位,也就是說(shuō)靡努,對(duì)于一個(gè)在Java中的int數(shù)據(jù)坪圾,做32次移位晓折,那么這個(gè)int數(shù)據(jù)就完全變了,以左移為例兽泄,左移是補(bǔ)0漓概,那么對(duì)于任意一個(gè)int類型數(shù)據(jù),做32次移位病梢,那么int數(shù)據(jù)變成32位全0的數(shù)據(jù)胃珍,Java不允許一次性移位左操作數(shù)的所有位,也就是右操作數(shù)不能大于32蜓陌。于是回到上述的句子觅彰,其指的是右操作數(shù)的低5位,5位二進(jìn)制所代表的最大值為2^5-1钮热,為31填抬,所以取右操作數(shù)的低5位,就是只看右操作數(shù)的二進(jìn)制的低5位隧期,其數(shù)值不會(huì)超過(guò)2^5次方飒责,也就是int的32位。因此仆潮,移位操作符進(jìn)行移位的實(shí)際次數(shù)读拆,其實(shí)是右操作數(shù)2的次數(shù)。

對(duì)上面那段話的理解是:移位操作符操作的運(yùn)算對(duì)象是二進(jìn)制的“位”鸵闪,int類型是32位也就是2的5次冪 檐晕!如果移32位以上,那么原來(lái)的數(shù)的信息會(huì)全部丟失蚌讼,這樣也就沒(méi)有什么意義了辟灰!所以上面的“只有右側(cè)的5個(gè)低位才會(huì)有用”說(shuō)的是:移位操作符右端的那個(gè)數(shù)(化成二進(jìn)制)的低5位才有用,即

X < <y;

是指y的低5位才有用篡石,即不能大于32芥喇。 而對(duì)于long型也是同樣的道理!

因此凰萨,如果對(duì)一個(gè)int 型继控,進(jìn)行移位,X < <y; 當(dāng)y小于32時(shí)胖眷,移位后的結(jié)果一般都在我們的預(yù)料當(dāng)中武通;而如果y大于32時(shí),由于移位超出了int所能表示的范圍珊搀,這時(shí)就先把y化成二進(jìn)制數(shù)冶忱,然后取該二進(jìn)制數(shù)右端的低5位,再把這5位化成十進(jìn)制境析,此時(shí)的這個(gè)十進(jìn)制就是要對(duì)X移動(dòng)的位數(shù)囚枪。

例如:

intinta=140;

a << 34System.out.println(Integer.toBinaryString(a << b));

上面那兩個(gè)語(yǔ)句的執(zhí)行過(guò)程是:先把a(bǔ)化成二進(jìn)制數(shù):10001100

執(zhí)行語(yǔ)句 a << 34 對(duì)a左移32位時(shí)派诬,先把 34化成二進(jìn)制:100010,對(duì)該二進(jìn)制數(shù)取右邊5位链沼,即00010默赂,化成十進(jìn)制數(shù)為2,所以實(shí)際上是對(duì)a左移兩位±ㄉ祝現(xiàn)在缆八,地球人都會(huì)知道上面程序的輸出結(jié)果是:1000110000

//////////////////////////////////////////////////

移位運(yùn)算符和按位運(yùn)算符一樣,同屬于位運(yùn)算符朝刊,因此移位運(yùn)算符的位指的也是二進(jìn)制位耀里。它包括以下幾種:

左移位(<<):將操作符左側(cè)的操作數(shù)向左移動(dòng)操作符右側(cè)指定的位數(shù)?。移動(dòng)的規(guī)則是在二進(jìn)制的低位補(bǔ)0拾氓。

有符號(hào)右移位(>>):將操作符左側(cè)的操作數(shù)向右移動(dòng)操作符右側(cè)指定的位數(shù)冯挎。移動(dòng)的規(guī)則是,如果被操作數(shù)的符號(hào)為正咙鞍,則在二進(jìn)制的高位補(bǔ)0房官;如果被操作數(shù)的符號(hào)為負(fù),則在二進(jìn)制的高位補(bǔ)1续滋。

無(wú)符號(hào)右移位(>>>):將操作符左側(cè)的操作數(shù)向右移動(dòng)操作符右側(cè)指定的位數(shù)翰守。移動(dòng)的規(guī)則是,無(wú)論被操作數(shù)的符號(hào)是正是負(fù)疲酌,都在二進(jìn)制位的高位補(bǔ)0蜡峰。

注意,移位運(yùn)算符不存在“無(wú)符號(hào)左移位(<<<)”一說(shuō)朗恳。與按位運(yùn)算符一樣湿颅,移位運(yùn)算符可以用于byte、short粥诫、int油航、long等整數(shù)類型,和字符串類型char怀浆,但是不能用于浮點(diǎn)數(shù)類型float谊囚、double;當(dāng)然执赡,在Java5.0及以上版本中镰踏,移位運(yùn)算符還可用于byte、short搀玖、int余境、long、char對(duì)應(yīng)的包裝器類灌诅。我們可以參照按位運(yùn)算符的示例寫一個(gè)測(cè)試程序來(lái)驗(yàn)證芳来,這里就不再舉例了。

與按位運(yùn)算符不同的是猜拾,移位運(yùn)算符不存在短路不短路的問(wèn)題即舌。

寫到這里就不得不提及一個(gè)在面試題中經(jīng)常被考到的題目:

請(qǐng)用最有效率的方法計(jì)算出2乘以8等于幾?這里所謂的最有效率挎袜,實(shí)際上就是通過(guò)最少顽聂、最簡(jiǎn)單的運(yùn)算得出想要的結(jié)果,而移位是計(jì)算機(jī)中相當(dāng)基礎(chǔ)的運(yùn)算了盯仪,用它來(lái)實(shí)現(xiàn)準(zhǔn)沒(méi)錯(cuò)了紊搪。左移位“<<”把被操作數(shù)每向左移動(dòng)一位,效果等同于將被操作數(shù)乘以2全景,而2*8=(2*2*2*2)耀石,就是把2向左移位3次。因此最有效率的計(jì)算2乘以8的方法就是“2<<3”爸黄。

最后滞伟,我們?cè)賮?lái)考慮一種情況,當(dāng)要移位的位數(shù)大于被操作數(shù)對(duì)應(yīng)數(shù)據(jù)類型所能表示的最大位數(shù)時(shí)炕贵,結(jié)果會(huì)是怎樣呢梆奈?比如,1<<35=?呢称开?

這里就涉及到移位運(yùn)算的另外一些規(guī)則:

byte亩钟、short、char在做移位運(yùn)算之前鳖轰,會(huì)被自動(dòng)轉(zhuǎn)換為int類型清酥,然后再進(jìn)行運(yùn)算。 byte脆霎、short总处、int、char類型的數(shù)據(jù)經(jīng)過(guò)移位運(yùn)算后結(jié)果都為int型睛蛛。 long經(jīng)過(guò)移位運(yùn)算后結(jié)果為long型鹦马。

在左移位(<<)運(yùn)算時(shí),如果要移位的位數(shù)大于被操作數(shù)對(duì)應(yīng)數(shù)據(jù)類型所能表示的最大位數(shù)忆肾,那么先將要求移位數(shù)對(duì)該類型所能表示的最大位數(shù)求余后荸频,再將被操作數(shù)移位所得余數(shù)對(duì)應(yīng)的數(shù)值,效果不變客冈。

比如1<<35=1<&lt;(352)=1<<3=8旭从。 對(duì)于有符號(hào)右移位(>>)運(yùn)算和無(wú)符號(hào)右移位(>>>)運(yùn)算,當(dāng)要移位的位數(shù)大于被操作數(shù)對(duì)應(yīng)數(shù)據(jù)類型所能表示的最大位數(shù)時(shí),那么先將要求移位數(shù)對(duì)該類型所能表示的最大位數(shù)求余后和悦,再將被操作數(shù)移位所得余數(shù)對(duì)應(yīng)的數(shù)值退疫,效果不變。鸽素。

比如100>>35=100>>(352)=100>>3=12褒繁。

? ? //以二進(jìn)制(基數(shù) 2)無(wú)符號(hào)整數(shù)形式返回一個(gè)整數(shù)參數(shù)的字符串表示形式。

? ? //如果參數(shù)為負(fù)馍忽,該無(wú)符號(hào)整數(shù)值為參數(shù)加上 2^32棒坏;否則等于該參數(shù)。? ? ? ? System.out.println(Integer.toBinaryString(-1)) ;

? ? ? ? System.out.println(Integer.toBinaryString(2)) ;

? ? ? ? System.out.println(Integer.toBinaryString(1)) ;

? ? 輸出:

? ? ? ? 11111111111111111111111111111111

? ? ? ? 11111111111111111111111111111110

? ? ? ? 1

結(jié)論輸出的是數(shù)字的二進(jìn)制補(bǔ)碼遭笋。為什么說(shuō)是以?二進(jìn)制無(wú)符號(hào)整數(shù)形式?返回一個(gè)?整數(shù)類型的字符串坝冕,為什么?如果參數(shù)為負(fù)數(shù),就要加上 232?次方瓦呼?

因?yàn)镴ava里的int是有符號(hào)的喂窟,在內(nèi)存中沒(méi)有正負(fù)之分,只有0/1吵血,整數(shù)是用補(bǔ)碼表示的

正數(shù)補(bǔ)碼等于原碼

負(fù)數(shù)的補(bǔ)碼等于其絕對(duì)值的反碼+1谎替,正好等于自身+2^32(對(duì)于4字節(jié)的整型來(lái)說(shuō))

-1的補(bǔ)碼 就是絕對(duì)值1的反碼(按位取反)11111111 11111111 11111111 11111110再+1

等于11111111 11111111 11111111 11111111

這樣正好能把最高位為1的數(shù)字用來(lái)表示負(fù)數(shù),而最高位為0的數(shù)字表示非負(fù)數(shù)

10000000 00000000 00000000 00000000 => -2147483648

11111111 11111111 11111111 11111111 => -1

00000000 00000000 00000000 00000000 => 0

00000000 00000000 00000000 00000001 => 1

01111111 11111111 11111111 11111111 => 2147483647

因此負(fù)數(shù)+2^32之后的二進(jìn)制串蹋辅,就是該負(fù)數(shù)內(nèi)存中準(zhǔn)確的存儲(chǔ)形式

對(duì)于上面的操作???a << 34 對(duì)a左移32位 有的人會(huì)有疑問(wèn)钱贯?不是應(yīng)該左移34位嗎?二進(jìn)制數(shù)取右邊5位侦另,為什么是右5位呢秩命? 為了解答你的問(wèn)題,請(qǐng)看下面:

1.對(duì)char褒傅,byte或者short進(jìn)行移位處理弃锐,那么在移位進(jìn)行之前,它們會(huì)自動(dòng)轉(zhuǎn)換成一個(gè)int殿托。只有右側(cè)的5個(gè)低位才會(huì)有用霹菊。這樣可防止我們?cè)谝粋€(gè)int數(shù)里移動(dòng)不切實(shí)際的位數(shù)。若對(duì)一個(gè)long值進(jìn)行處理支竹,最后得到的結(jié)果也是long旋廷。此時(shí)只會(huì)用到右側(cè)的6個(gè)低位,防止移動(dòng)超過(guò)long值里現(xiàn)成的位數(shù)礼搁。

2.移位操作符能操作的數(shù)只有int類型和long類型饶碘,這個(gè)是指左操作數(shù)的類型。對(duì)于int類型而言馒吴,int在Java中占4字節(jié)扎运,一共32位瑟曲,也就是說(shuō),對(duì)于一個(gè)在Java中的int數(shù)據(jù)豪治,做32次移位洞拨,那么這個(gè)int數(shù)據(jù)就完全變了,以左移為例鬼吵,左移是補(bǔ)0扣甲,那么對(duì)于任意一個(gè)int類型數(shù)據(jù)篮赢,做32次移位齿椅,那么int數(shù)據(jù)變成32位全0的數(shù)據(jù),Java不允許一次性移位左操作數(shù)的所有位启泣,也就是右操作數(shù)不能大于32涣脚。于是回到上述的句子,其指的是右操作數(shù)的低5位寥茫,5位二進(jìn)制所代表的最大值為2^5-1遣蚀,為31,所以取右操作數(shù)的低5位纱耻,就是只看右操作數(shù)的二進(jìn)制的低5位芭梯,其數(shù)值不會(huì)超過(guò)2^5次方,也就是int的32位弄喘。因此玖喘,移位操作符進(jìn)行移位的實(shí)際次數(shù),其實(shí)是右操作數(shù)2的次數(shù)

3.移位操作符操作的運(yùn)算對(duì)象是二進(jìn)制的“位”蘑志,int類型是32位也就是2的5次冪 累奈!如果移32位以上,那么原來(lái)的數(shù)的信息會(huì)全部丟失急但,這樣也就沒(méi)有什么意義了澎媒!所以上面的“只有右側(cè)的5個(gè)低位才會(huì)有用”說(shuō)的是:移位操作符右端的那個(gè)數(shù)(化成二進(jìn)制)的低5位才有用,即

X < <y;

是指y的低5位才有用波桩,即不能大于32戒努。 而對(duì)于long型也是同樣的道理!

因此镐躲,如果對(duì)一個(gè)int 型储玫,進(jìn)行移位,X < <y; 當(dāng)y小于32時(shí)匀油,移位后的結(jié)果一般都在我們的預(yù)料當(dāng)中缘缚;而如果y大于32時(shí),由于移位超出了int所能表示的范圍敌蚜,這時(shí)就先把y化成二進(jìn)制數(shù)桥滨,然后取該二進(jìn)制數(shù)右端的低5位,再把這5位化成十進(jìn)制,此時(shí)的這個(gè)十進(jìn)制就是要對(duì)X移動(dòng)的位數(shù)齐媒。

java中二進(jìn)制轉(zhuǎn)十進(jìn)制:Integer.toBinaryString(34) //100010十進(jìn)制轉(zhuǎn)二進(jìn)制:Integer.valueOf("00010",2) //2

ps:轉(zhuǎn)發(fā)自?https://www.cnblogs.com/winsker/p/6728672.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蒲每,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子喻括,更是在濱河造成了極大的恐慌邀杏,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唬血,死亡現(xiàn)場(chǎng)離奇詭異望蜡,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)拷恨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門脖律,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人腕侄,你說(shuō)我怎么就攤上這事小泉。” “怎么了冕杠?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵微姊,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我分预,道長(zhǎng)兢交,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任噪舀,我火速辦了婚禮魁淳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘与倡。我一直安慰自己界逛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布纺座。 她就那樣靜靜地躺著息拜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪净响。 梳的紋絲不亂的頭發(fā)上少欺,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音馋贤,去河邊找鬼赞别。 笑死,一個(gè)胖子當(dāng)著我的面吹牛配乓,可吹牛的內(nèi)容都是我干的仿滔。 我是一名探鬼主播惠毁,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼崎页!你這毒婦竟也來(lái)了鞠绰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤飒焦,失蹤者是張志新(化名)和其女友劉穎蜈膨,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牺荠,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翁巍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了志电。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片曙咽。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖挑辆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情孝情,我是刑警寧澤鱼蝉,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站箫荡,受9級(jí)特大地震影響魁亦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜羔挡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一洁奈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绞灼,春花似錦利术、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至军掂,卻和暖如春轮蜕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蝗锥。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工跃洛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人终议。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓汇竭,卻偏偏與公主長(zhǎng)得像闲延,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子韩玩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容