Java 位移運算符

本人只是 Android小菜一個,寫技術文檔只是爲了總結本身在最近學習到的知識,歷來不敢爲人師,若是裏面有些不正確的地方請你們盡情指出,謝謝!java

1.概述

Java 位移運算符是Java中基本的位運算操做,可是平時工做中沒有直接使用到,因此一直對其沒有仔細研究過,對其實現也並不清楚。最近打算學習下HashMap的實現原理,發現裏面有些代碼用到了位移操做,下面的代碼用到了無符號右移,第一次看到這段代碼的時候徹底不瞭解這個右移到底要達到什麼效果。學習

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
複製代碼

小菜打算正好藉着這個機會,好好學習下Java中的位移操做,首先要明白位移運算只能應用在long,int,short,char,byte這幾種數據類型,並且當要應用在short,char和byte時,首先會把他們拓展成int再進行運算。Java的位移運算具體包含下面幾種:spa

操做符 名稱 含義 例子
<< 左移運算符 把操做數的二進制按位左移指定位數,並用零在右邊進行補齊 60 << 2
>> 右移運算符 把操做數的二進制按位右移指定位數,並用符號位在左邊進行補齊 60 >> 2
>>> 無符號右移運算符 把操做數的二進制按位右移指定位數,並用零在左邊進行補齊 60 >>> 2

2. 左移運算符

左移運算就是把操做數按位進行左移,左邊的位將被移除,後邊新增位用零進行補齊,下圖演示了一個左移過程:code

左移運算示例
因爲位移操做針對的二進制數據,在示例中直接使用二進制數進行演示,分別演示了「左移1位」,「左移2位」,「左移3位」幾種狀況。


在左移1位的過程當中,因爲最左位表明是符號位,在左移的過程當中這個符號位丟失,直接使用原來左二位做爲符號位,同時用零在右邊補齊,最終致使的結果原來的正整型數變成了負整型數.cdn

能夠用代碼進行驗證:blog

int source = 1740967785; // 二進制爲:01100111110001010000111101101001
    Log.i(TAG, Integer.toBinaryString(source) + " << 1 : " + Integer.toBinaryString(source << 1) + " : " + (source << 1));

    Android_Test: 1100111110001010000111101101001 << 1 : 11001111100010100001111011010010 : -813031726
複製代碼

能夠看到因爲在左移1位的過程當中致使符號位發生了變化,原來的正數變成了負數。細心的讀者可能會發如今輸出中,原數據並無輸出咱們指望的32位二進制而是隻有31位,這是由於其符號位是0,在輸出過程當中被忽略了。文檔


在左移2位的過程當中,和左移1位比較相似,也會引發符號位的變化,這裏直接給出驗證結果:string

int source = 1740967785; // 二進制爲:01100111110001010000111101101001
    Log.i(TAG, Integer.toBinaryString(source) + " << 2 : " + Integer.toBinaryString(source << 2) + " : " + (source << 2));

    Android_Test: 1100111110001010000111101101001 << 2 : 10011111000101000011110110100100 : -1626063452
複製代碼

在左移3位的過程當中,從上面的示例圖能夠看到,符號位沒有發生變化,右邊直接用零對齊,其驗證結果以下:hash

Log.i(TAG, Integer.toBinaryString(source) + " << 3 : " + Integer.toBinaryString(source << 3) + " : " + (source << 3));
    
    Android_Test: 1100111110001010000111101101001 << 3 : 111110001010000111101101001000 : 1042840392
複製代碼

從上面的演示結果能夠發現:在左移過程當中,數據的符號位有可能發生變化,最終的結果就是發生由正到負或者由負到正的轉變,並非直觀上認爲的是原來的2倍。所謂的左移1位變爲原來的2倍這個結論只適用了較小的正整數,由於它們在最初的幾回左移過程當中不會發生符號位的變化。it

3. 右移運算符

右移運算就是把操做數按位右移,右邊的位將被移除,左邊新增位用符號位補齊,下圖演示了一個右移過程:

右移運算示例
圖中演示了右移1位的操做,包括「正整數右移1位」和「負整數右移1位」,能夠看到在右移的過程當中右邊會有位被移出,但左邊會用對應的符號位進行補齊,若是操做數是正數就用0補齊,反之就用1補齊,這也就說明在整個右移過程當中不會改變操做數的符號,正數始終爲正,負數始終爲負。

int source = 0b01100111110001010000111101101001;
    Log.i(TAG, Integer.toBinaryString(source) + " >> 1 = " + Integer.toBinaryString(source >> 1) + " ; " + source + " >> 1 = " + (source >> 1));
    
    Android_Test: 1100111110001010000111101101001 >> 1 = 110011111000101000011110110100 ; 1740967785 >> 1 = 870483892
複製代碼

這段代碼中操做數是正數,進行右移一位操做後,結果仍然是正數而且是原操做數的一半。


int source = 0b11100111110001010000111101101001;
    Log.i(TAG, Integer.toBinaryString(source) + " >> 1 = " + Integer.toBinaryString(source >> 1) + " ; " + source + " >> 1 = " + (source >> 1));
    
    Android_Test: 11100111110001010000111101101001 >> 1 = 11110011111000101000011110110100 ; -406515863 >> 1 = -203257932
複製代碼

這段代碼中操做數是負數,進行右移一位操做後,結果仍然是負數而且是原操做數的一半。

從上面的分析和代碼驗證狀況看,右移過程當中,操做數始終保持符號不變,且每右移一位,就變爲原操做數的一半。

4. 無符號右移運算

無符號右移運算相比較右移運算更加簡單,由於其在右移過程當中直接在左邊用0補齊便可,無須考慮當前操做數的符號,下圖演示了一個無符號右移過程:

圖中演示了無符號右移4位的過程,包括「正整數無符號右移4位」和「負整數無符號右移4位」,能夠看到在無符號右移過程當中,右邊爲直接移除,左邊位直接用0補齊,這就保證了不管原操做數的符號位是什麼在右移後都是0,即移動後都是正數。

int source = 0b01100111110001010000111101101001;
    int source_2 = 0b11100111110001010000111101101001;
    Log.i(TAG, Integer.toBinaryString(source) + " >>> 4 = " + Integer.toBinaryString(source >>> 4) + " ; " + source + " >>> 4 = " + (source >>> 4));
    Log.i(TAG, Integer.toBinaryString(source_2) + " >>> 4 = " + Integer.toBinaryString(source_2 >>> 4) + " ; " + source_2 + " >>> 4 = " + (source_2 >>> 4));
    
    Android_Test: 1100111110001010000111101101001 >>> 4 = 110011111000101000011110110 ; 1740967785 >>> 4 = 108810486
    Android_Test: 11100111110001010000111101101001 >>> 4 = 1110011111000101000011110110 ; -406515863 >>> 4 = 243028214
複製代碼

5. 總結

本文主要介紹了Java中的位移運算符,包括「<< 左移運算符」,「>> 右移運算符」和「>>> 無符號右移運算符」,在使用過程當中要注意「補齊方式」和補齊後操做數的符號,簡單總結以下:

操做符 補齊方式 結果符號
<< 右邊用 0 補齊 和原操做數沒有絕對關係,取決於左移後符號位。
>> 左邊有原符號位補齊 和原操做數有相同符號。
>>> 左邊用 0 補齊 和原操做數無關,一直爲正數。
相關文章
相關標籤/搜索