更新時(shí)間:2020-10-13 17:21:37 來源:動(dòng)力節(jié)點(diǎn) 瀏覽1228次
移位操作是把數(shù)據(jù)看作二進(jìn)制數(shù),然后將其向左或向右移動(dòng)若干位的運(yùn)算。在Java中,移位運(yùn)算符包含三種:<<左移運(yùn)算符,>>帶符號右移運(yùn)算符,>>>無符號右移運(yùn)算符。這三種操作符都只能作用于long,int,short,byte這四種基本整形類型上和char類型上。下面我們來詳細(xì)介紹這三種移位運(yùn)算符。
1.左移操作符<<
左移操作符<<是將數(shù)據(jù)轉(zhuǎn)換為二進(jìn)制后,向左移動(dòng)若干位,高位丟棄,低位補(bǔ)零。
首先我們可以利用java中的方法獲取一個(gè)數(shù)的二進(jìn)制:Integer.toBinaryString(int val)。
然后我們看下面這個(gè)例子:
public static void main(String[] args) {
int a = 10;
System.out.println("左移前的二進(jìn)制:"+Integer.toBinaryString(a));
a <<= 2;
System.out.println("左移后的二進(jìn)制:"+Integer.toBinaryString(a));
System.out.println("左移后的十進(jìn)制:"+a);
}
首先定義一個(gè)數(shù),值為10,打印它的二進(jìn)制(1010),然后進(jìn)行左移操作2位。打印移位后的結(jié)果和二進(jìn)制。
左移前的二進(jìn)制:1010
左移后的二進(jìn)制:101000
左移后的十進(jìn)制:40
可以看出,將原來的二進(jìn)制向左移動(dòng)了兩位,后面進(jìn)行了補(bǔ)零。40=10 * 2 * 2。所以一次左移等于將這個(gè)數(shù)擴(kuò)大了兩倍。對于左移N位,就等于乘以2^n,如40=10*2^2。再來看一個(gè)負(fù)數(shù)的左移:
int b = -8;
System.out.println("左移前的二進(jìn)制:" + Integer.toBinaryString(b));
b <<= 2;
System.out.println("左移后的二進(jìn)制:" + Integer.toBinaryString(b));
System.out.println("左移后的十進(jìn)制:" + b);
我們定義了一個(gè)負(fù)數(shù)(-8),打印出它的二進(jìn)制,進(jìn)行左移2位,左移后打印它的二進(jìn)制,再將10進(jìn)制打印出來查看。
左移前的二進(jìn)制:11111111111111111111111111111000
左移后的二進(jìn)制:11111111111111111111111111100000
左移后的十進(jìn)制:-32
可以明顯的看出二進(jìn)制向左移動(dòng)了兩位,前面的位置丟棄,后面的位置補(bǔ)零。轉(zhuǎn)換為10進(jìn)制也符合我們之前的運(yùn)算:-32 = -8 * 2 *2。
2.帶符號右移操作符>>
剛才的左移中,它向左移動(dòng),高位進(jìn)行了丟棄,低位進(jìn)行補(bǔ)零。但是右移操作時(shí)有一個(gè)符號位,操作不當(dāng)將造成答案與預(yù)期結(jié)果不同。
帶符號右移就是在**向右移動(dòng)若干位,低位進(jìn)行丟棄,高位按照符號位進(jìn)行填補(bǔ)。**對于正數(shù)做右移操作時(shí),高位補(bǔ)充0;負(fù)數(shù)進(jìn)行右移時(shí),高位補(bǔ)充1。
再來用例子證明一下:
public static void main(String[] args) {
int a = 1024;
System.out.println("a右移前的二進(jìn)制:" + Integer.toBinaryString(a));
a >>= 4;
System.out.println("a右移后的二進(jìn)制:" + Integer.toBinaryString(a));
System.out.println("a右移后的十進(jìn)制:"+a);
int b = -70336;
System.out.println("b右移前的二進(jìn)制:" + Integer.toBinaryString(b));
b >>= 4;
System.out.println("b右移后的二進(jìn)制:" + Integer.toBinaryString(b));
System.out.println("b右移后的十進(jìn)制:"+b);
}
定義了兩個(gè)變量,a=1024,然后向右移動(dòng)4位。b=-70336也向右移動(dòng)4位。分別將它們的移動(dòng)前后二進(jìn)制和十進(jìn)制打印出來查看。
a右移前的二進(jìn)制:10000000000
a右移后的二進(jìn)制:1000000
a右移后的十進(jìn)制:64
b右移前的二進(jìn)制:11111111111111101110110101000000
b右移后的二進(jìn)制:11111111111111111110111011010100
b右移后的十進(jìn)制:-4396
a原來的二進(jìn)制向右移動(dòng)后,低位被丟棄,高位補(bǔ)充符號位也就是0。b原來的二進(jìn)制向右移動(dòng)后,低位被丟棄,高位補(bǔ)充符號位1。這也符號我們之前的運(yùn)算規(guī)律:
1024 / 2^4^ =16 ;-70336/ 2^4^ = -4396。
3.無符號右移操作符>>>
剛才的帶符號右移操作符,我們在向右移動(dòng)時(shí)帶著高位的符號,正數(shù)填充0,負(fù)數(shù)填充1。現(xiàn)在不帶符號的右移操作符大體與右移操作符一致,只不過不再區(qū)分正負(fù)數(shù),結(jié)果都是高位補(bǔ)零,低位丟棄。
再用例子來證明一下:
public static void main(String[] args) {
int a = 1024;
System.out.println("a右移前的二進(jìn)制:" + Integer.toBinaryString(a));
a >>>= 4;
System.out.println("a右移后的二進(jìn)制:" + Integer.toBinaryString(a));
System.out.println("a右移后的十進(jìn)制:"+a);
int b = -70336;
System.out.println("b右移前的二進(jìn)制:" + Integer.toBinaryString(b));
b >>>= 4;
System.out.println("b右移后的二進(jìn)制:" + Integer.toBinaryString(b));
System.out.println("b右移后的十進(jìn)制:"+b);
}
還是剛才帶符號右移的例子:這次我們僅僅把操作符換成無符號的右移操作符。
按照定義,其實(shí)在正數(shù)時(shí)不會(huì)有變化,因?yàn)樵趲Х柕挠乙浦姓龜?shù)也是高位補(bǔ)零。只不過當(dāng)值為負(fù)數(shù)時(shí)會(huì)有變化,讓我們看一下輸出是不是符合猜想。
a右移前的二進(jìn)制:10000000000
a右移后的二進(jìn)制:1000000
a右移后的十進(jìn)制:64
b右移前的二進(jìn)制:11111111111111101110110101000000
b右移后的二進(jìn)制:1111111111111110111011010100
b右移后的十進(jìn)制:268431060
確實(shí)正數(shù)沒有變化,驗(yàn)證了我們的猜想。然后是負(fù)數(shù),這次向右移動(dòng)時(shí)高位進(jìn)行了補(bǔ)零,低位丟棄。改變后的數(shù)值不再符合我們之前的規(guī)律。
在無符號右移中,當(dāng)值為正數(shù)時(shí),依然符合之前的規(guī)律移動(dòng)一位相當(dāng)于除以2。但是當(dāng)值為負(fù)數(shù)時(shí)不再符合規(guī)律。
當(dāng)移位的位數(shù)超過數(shù)值所占用的位數(shù)會(huì)怎么樣?
這個(gè)問題很有意思,我們剛剛都僅僅移動(dòng)了2位或者4位,如果我們超過了int的位數(shù)也就是32位后會(huì)怎么樣?我們?nèi)绻麑σ粋€(gè)正數(shù)左移32位,低位補(bǔ)零補(bǔ)充了32次就變成0了,就如同下面代碼所寫的一樣,最終a的結(jié)果會(huì)是什么。會(huì)變成0嗎?
public static void main(String[] args) {
int a = 10;
a <<= 32;
System.out.println(a);
}
經(jīng)過我們運(yùn)行后發(fā)現(xiàn)a的結(jié)果最終沒變還是10。我們?nèi)绻某勺笠?3位,它的結(jié)果會(huì)變成20。那么它的運(yùn)算規(guī)律會(huì)不會(huì)是當(dāng)超過位數(shù)后僅僅移動(dòng)對位數(shù)的余數(shù)呢?比如對int做操作,它實(shí)際是運(yùn)算 位數(shù)%32次。
經(jīng)過多次試驗(yàn)發(fā)現(xiàn)答案確實(shí)就是這個(gè)猜想,當(dāng)對int類型處理時(shí),右移x位的運(yùn)算為x%32位。
對其他類型也是一樣嗎?
我們剛才都是用的int類型,那么對于byte,short,char,long都一樣嗎?
事實(shí)上,Java在對byte,short,char這三種類型進(jìn)行移位操作前,會(huì)將其先轉(zhuǎn)型為int類型,然后再進(jìn)行位操作。由于我們有進(jìn)行了重新賦值將其賦值為原來的byte類型,所以又進(jìn)行了從int到byte的先下轉(zhuǎn)型,也就是截?cái)唷N覀儗ι厦娴睦舆M(jìn)行一下修改可以更直觀的發(fā)現(xiàn)運(yùn)行過程:
public static void main(String[] args) {
byte b = -1;
System.out.println("操作前十進(jìn)制:"+b);
System.out.println("操作前二進(jìn)制:"+Integer.toBinaryString(b));
System.out.println("進(jìn)行無符號右移6位后的十進(jìn)制:"+(b>>>6));
System.out.println("操作后二進(jìn)制:"+Integer.toBinaryString(b>>>6));
}
在這里我沒有使用=進(jìn)行重新賦值,而是計(jì)算完成后直接打印十進(jìn)制和二進(jìn)制的結(jié)果。
操作前十進(jìn)制:-1
操作前二進(jìn)制:11111111111111111111111111111111
進(jìn)行無符號右移6位后的十進(jìn)制:67108863
操作后二進(jìn)制:11111111111111111111111111
從打印結(jié)果中可以明顯的看出是先轉(zhuǎn)換為int類型,然后進(jìn)行位運(yùn)算,位運(yùn)算結(jié)束后由于重新賦值所以進(jìn)行的截?cái)唷?/p>
對于long類型,它是64位,不用先轉(zhuǎn)換。
我們不難得出結(jié)論,移位符是Java中的基本操作符,實(shí)際支持的類型只有int和long。在對byte,short,char類型進(jìn)行移位操作時(shí),都會(huì)先將其轉(zhuǎn)換為int類型再進(jìn)行操作。左移<<操作符相當(dāng)于乘以2。帶符號右移操作符>>相當(dāng)于除以2。在Java中使用位運(yùn)算符會(huì)比乘*,除/運(yùn)算符更高效一些。而無符號右移符>>>在移動(dòng)時(shí)高位補(bǔ)零,低位丟棄,在正數(shù)時(shí)仍然相當(dāng)于除以2,但是在負(fù)數(shù)時(shí)結(jié)果卻是變大了(由負(fù)數(shù)變?yōu)檎龜?shù))。
本文對三種移位運(yùn)算符進(jìn)行了詳細(xì)地講解,事實(shí)上,在講解的過程中用到我們之前學(xué)習(xí)的一些Java基礎(chǔ)知識(shí),比如說Java的移位操作,以及各個(gè)進(jìn)制的轉(zhuǎn)換。對于,Java零基礎(chǔ)的小伙伴來說,不要急于求成,學(xué)習(xí)更高難度的知識(shí),而是應(yīng)該返璞歸真,從基礎(chǔ)開始,打好基礎(chǔ)才能鑄就輝煌。
初級 202925
初級 203221
初級 202629
初級 203743