更新時間:2020-10-13 17:21:37 來源:動力節點 瀏覽1182次
移位操作是把數據看作二進制數,然后將其向左或向右移動若干位的運算。在Java中,移位運算符包含三種:<<左移運算符,>>帶符號右移運算符,>>>無符號右移運算符。這三種操作符都只能作用于long,int,short,byte這四種基本整形類型上和char類型上。下面我們來詳細介紹這三種移位運算符。
1.左移操作符<<
左移操作符<<是將數據轉換為二進制后,向左移動若干位,高位丟棄,低位補零。
首先我們可以利用java中的方法獲取一個數的二進制:Integer.toBinaryString(int val)。
然后我們看下面這個例子:
public static void main(String[] args) {
int a = 10;
System.out.println("左移前的二進制:"+Integer.toBinaryString(a));
a <<= 2;
System.out.println("左移后的二進制:"+Integer.toBinaryString(a));
System.out.println("左移后的十進制:"+a);
}
首先定義一個數,值為10,打印它的二進制(1010),然后進行左移操作2位。打印移位后的結果和二進制。
左移前的二進制:1010
左移后的二進制:101000
左移后的十進制:40
可以看出,將原來的二進制向左移動了兩位,后面進行了補零。40=10 * 2 * 2。所以一次左移等于將這個數擴大了兩倍。對于左移N位,就等于乘以2^n,如40=10*2^2。再來看一個負數的左移:
int b = -8;
System.out.println("左移前的二進制:" + Integer.toBinaryString(b));
b <<= 2;
System.out.println("左移后的二進制:" + Integer.toBinaryString(b));
System.out.println("左移后的十進制:" + b);
我們定義了一個負數(-8),打印出它的二進制,進行左移2位,左移后打印它的二進制,再將10進制打印出來查看。
左移前的二進制:11111111111111111111111111111000
左移后的二進制:11111111111111111111111111100000
左移后的十進制:-32
可以明顯的看出二進制向左移動了兩位,前面的位置丟棄,后面的位置補零。轉換為10進制也符合我們之前的運算:-32 = -8 * 2 *2。
2.帶符號右移操作符>>
剛才的左移中,它向左移動,高位進行了丟棄,低位進行補零。但是右移操作時有一個符號位,操作不當將造成答案與預期結果不同。
帶符號右移就是在**向右移動若干位,低位進行丟棄,高位按照符號位進行填補。**對于正數做右移操作時,高位補充0;負數進行右移時,高位補充1。
再來用例子證明一下:
public static void main(String[] args) {
int a = 1024;
System.out.println("a右移前的二進制:" + Integer.toBinaryString(a));
a >>= 4;
System.out.println("a右移后的二進制:" + Integer.toBinaryString(a));
System.out.println("a右移后的十進制:"+a);
int b = -70336;
System.out.println("b右移前的二進制:" + Integer.toBinaryString(b));
b >>= 4;
System.out.println("b右移后的二進制:" + Integer.toBinaryString(b));
System.out.println("b右移后的十進制:"+b);
}
定義了兩個變量,a=1024,然后向右移動4位。b=-70336也向右移動4位。分別將它們的移動前后二進制和十進制打印出來查看。
a右移前的二進制:10000000000
a右移后的二進制:1000000
a右移后的十進制:64
b右移前的二進制:11111111111111101110110101000000
b右移后的二進制:11111111111111111110111011010100
b右移后的十進制:-4396
a原來的二進制向右移動后,低位被丟棄,高位補充符號位也就是0。b原來的二進制向右移動后,低位被丟棄,高位補充符號位1。這也符號我們之前的運算規律:
1024 / 2^4^ =16 ;-70336/ 2^4^ = -4396。
3.無符號右移操作符>>>
剛才的帶符號右移操作符,我們在向右移動時帶著高位的符號,正數填充0,負數填充1。現在不帶符號的右移操作符大體與右移操作符一致,只不過不再區分正負數,結果都是高位補零,低位丟棄。
再用例子來證明一下:
public static void main(String[] args) {
int a = 1024;
System.out.println("a右移前的二進制:" + Integer.toBinaryString(a));
a >>>= 4;
System.out.println("a右移后的二進制:" + Integer.toBinaryString(a));
System.out.println("a右移后的十進制:"+a);
int b = -70336;
System.out.println("b右移前的二進制:" + Integer.toBinaryString(b));
b >>>= 4;
System.out.println("b右移后的二進制:" + Integer.toBinaryString(b));
System.out.println("b右移后的十進制:"+b);
}
還是剛才帶符號右移的例子:這次我們僅僅把操作符換成無符號的右移操作符。
按照定義,其實在正數時不會有變化,因為在帶符號的右移中正數也是高位補零。只不過當值為負數時會有變化,讓我們看一下輸出是不是符合猜想。
a右移前的二進制:10000000000
a右移后的二進制:1000000
a右移后的十進制:64
b右移前的二進制:11111111111111101110110101000000
b右移后的二進制:1111111111111110111011010100
b右移后的十進制:268431060
確實正數沒有變化,驗證了我們的猜想。然后是負數,這次向右移動時高位進行了補零,低位丟棄。改變后的數值不再符合我們之前的規律。
在無符號右移中,當值為正數時,依然符合之前的規律移動一位相當于除以2。但是當值為負數時不再符合規律。
當移位的位數超過數值所占用的位數會怎么樣?
這個問題很有意思,我們剛剛都僅僅移動了2位或者4位,如果我們超過了int的位數也就是32位后會怎么樣?我們如果對一個正數左移32位,低位補零補充了32次就變成0了,就如同下面代碼所寫的一樣,最終a的結果會是什么。會變成0嗎?
public static void main(String[] args) {
int a = 10;
a <<= 32;
System.out.println(a);
}
經過我們運行后發現a的結果最終沒變還是10。我們如果改成左移33位,它的結果會變成20。那么它的運算規律會不會是當超過位數后僅僅移動對位數的余數呢?比如對int做操作,它實際是運算 位數%32次。
經過多次試驗發現答案確實就是這個猜想,當對int類型處理時,右移x位的運算為x%32位。
對其他類型也是一樣嗎?
我們剛才都是用的int類型,那么對于byte,short,char,long都一樣嗎?
事實上,Java在對byte,short,char這三種類型進行移位操作前,會將其先轉型為int類型,然后再進行位操作。由于我們有進行了重新賦值將其賦值為原來的byte類型,所以又進行了從int到byte的先下轉型,也就是截斷。我們對上面的例子進行一下修改可以更直觀的發現運行過程:
public static void main(String[] args) {
byte b = -1;
System.out.println("操作前十進制:"+b);
System.out.println("操作前二進制:"+Integer.toBinaryString(b));
System.out.println("進行無符號右移6位后的十進制:"+(b>>>6));
System.out.println("操作后二進制:"+Integer.toBinaryString(b>>>6));
}
在這里我沒有使用=進行重新賦值,而是計算完成后直接打印十進制和二進制的結果。
操作前十進制:-1
操作前二進制:11111111111111111111111111111111
進行無符號右移6位后的十進制:67108863
操作后二進制:11111111111111111111111111
從打印結果中可以明顯的看出是先轉換為int類型,然后進行位運算,位運算結束后由于重新賦值所以進行的截斷。
對于long類型,它是64位,不用先轉換。
我們不難得出結論,移位符是Java中的基本操作符,實際支持的類型只有int和long。在對byte,short,char類型進行移位操作時,都會先將其轉換為int類型再進行操作。左移<<操作符相當于乘以2。帶符號右移操作符>>相當于除以2。在Java中使用位運算符會比乘*,除/運算符更高效一些。而無符號右移符>>>在移動時高位補零,低位丟棄,在正數時仍然相當于除以2,但是在負數時結果卻是變大了(由負數變為正數)。
本文對三種移位運算符進行了詳細地講解,事實上,在講解的過程中用到我們之前學習的一些Java基礎知識,比如說Java的移位操作,以及各個進制的轉換。對于,Java零基礎的小伙伴來說,不要急于求成,學習更高難度的知識,而是應該返璞歸真,從基礎開始,打好基礎才能鑄就輝煌。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習