<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我的漫漫程序之旅

    專注于JavaWeb開發
    隨筆 - 39, 文章 - 310, 評論 - 411, 引用 - 0
    數據加載中……

    Java位運算符精解

    package com;

    public class
     BitOperator
    {

        
    /**
         * 
    @param args
         
    */

        
    public static void main(String[] args)
        
    {
            
    //按位非,求補碼

            System.out.println(~20);
            
    //按位與運算

            System.out.println(4&2);
            
    //按位或運算符

            System.out.println(4|27);
            
    //按位異或運算

            System.out.println(4^2);
            
    //左位移運算

            System.out.println(4<<2);
            
    //右位移運算

            System.out.println(4>>2);
            
    //無符號右位移運算

            System.out.println(8>>>2);
        }


    }


    看看這段代碼會輸出什么?

    對位運算符不了解的朋友可能不太明白.
    Java位運算符的學習之旅吧.

    Java 定義的位運算(bitwise operators )直接對整數類型的位進行操作,這些整數類型包括long,int,short,char,and byte 。表4-2 列出了位運算:
    表4.2 位運算符及其結果

    運算符 結果
    ~ 按位非(NOT)(一元運算)
    & 按位與(AND)
    | 按位或(OR)
    ^ 按位異或(XOR)
    >> 右移
    >>> 右移,左邊空出的位以0填充
    運算符 結果
    << 左移
    &= 按位與賦值
    |= 按位或賦值
    ^= 按位異或賦值
    >>= 右移賦值
    >>>= 右移賦值,左邊空出的位以0填充
    <<= 左移賦值

    續表

    既然位運算符在整數范圍內對位操作,因此理解這樣的操作會對一個值產生什么效果是重要的。具體地說,知道Java 是如何存儲整數值并且如何表示負數的是有用的。因此,在繼續討論之前,讓我們簡短概述一下這兩個話題。

    所有的整數類型以二進制數字位的變化及其寬度來表示。例如,byte 型值42的二進制代碼是00101010 ,其中每個位置在此代表2的次方,在最右邊的位以20開始。向左下一個位置將是21,或2,依次向左是22,或4,然后是8,16,32等等,依此類推。因此42在其位置1,3,5的值為1(從右邊以0開始數);這樣42是21+23+25的和,也即是2+8+32 。

    所有的整數類型(除了char 類型之外)都是有符號的整數。這意味著他們既能表示正數,又能表示負數。Java 使用大家知道的2的補碼(two’s complement )這種編碼來表示負數,也就是通過將與其對應的正數的二進制代碼取反(即將1變成0,將0變成1),然后對其結果加1。例如,-42就是通過將42的二進制代碼的各個位取反,即對00101010 取反得到11010101 ,然后再加1,得到11010110 ,即-42 。要對一個負數解碼,首先對其所有的位取反,然后加1。例如-42,或11010110 取反后為00101001 ,或41,然后加1,這樣就得到了42。

    如果考慮到零的交叉(zero crossing )問題,你就容易理解Java (以及其他絕大多數語言)這樣用2的補碼的原因。假定byte 類型的值零用00000000 代表。它的補碼是僅僅將它的每一位取反,即生成11111111 ,它代表負零。但問題是負零在整數數學中是無效的。為了解決負零的問題,在使用2的補碼代表負數的值時,對其值加1。即負零11111111 加1后為100000000 。但這樣使1位太靠左而不適合返回到byte 類型的值,因此人們規定,-0和0的表示方法一樣,-1的解碼為11111111 。盡管我們在這個例子使用了byte 類型的值,但同樣的基本的原則也適用于所有Java 的整數類型。

    因為Java 使用2的補碼來存儲負數,并且因為Java 中的所有整數都是有符號的,這樣應用位運算符可以容易地達到意想不到的結果。例如,不管你如何打算,Java 用高位來代表負數。為避免這個討厭的意外,請記住不管高位的順序如何,它決定一個整數的符號。

    4.2.1 位邏輯運算符
    位邏輯運算符有“與”(AND)、“或”(OR)、“異或(XOR )”、“非(NOT)”,分別用“&”、“|”、“^”、“~”表示,4-3 表顯示了每個位邏輯運算的結果。在繼續討論之前,請記住位運算符應用于每個運算數內的每個單獨的位。
    表4-3 位邏輯運算符的結果

    0 1 0 1 B 0 0 1 1 A | B 0 1 1 1 A & B 0 0 0 1 A ^ B 0 1 1 0 ~1 0 1 0 


    按位非(NOT)

    按位非也叫做補,一元運算符NOT“~”是對其運算數的每一位取反。例如,數字42,它的二進制代碼為:

    00101010

    經過按位非運算成為

    11010101

    按位與(AND)

    按位與運算符“&”,如果兩個運算數都是1,則結果為1。其他情況下,結果均為零。看下面的例子:

    00101010 42 &00001111 15

    00001010 10

    按位或(OR)

    按位或運算符“|”,任何一個運算數為1,則結果為1。如下面的例子所示:

    00101010 42 | 00001111 15

    00101111 47

    按位異或(XOR)

    按位異或運算符“^”,只有在兩個比較的位不同時其結果是 1。否則,結果是零。下面的例子顯示了“^”運算符的效果。這個例子也表明了XOR 運算符的一個有用的屬性。注意第二個運算數有數字1的位,42對應二進制代碼的對應位是如何被轉換的。第二個運算數有數字0的位,第一個運算數對應位的數字不變。當對某些類型進行位運算時,你將會看到這個屬性的用處。

    00101010 42 ^ 00001111 15

    00100101 37
    位邏輯運算符的應用

    下面的例子說明了位邏輯運算符:

    // Demonstrate the bitwise logical operators. 
    class BitLogic 
    public static void main(String args[]) 


    String binary[] 
    = {"0000""0001""0010""0011""0100""0101""0110""0111""1000""1001""1010""1011""1100""1101""1110""1111" 

    }

    int a = 3// 0 + 2 + 1 or 0011 in binary 
    int b = 6// 4 + 2 + 0 or 0110 in binary 
    int c = a | b; 
    int d = a & b; 
    int e = a ^ b; 
    int f = (~& b) | (a & ~b); 
    int g = ~& 0x0f


    System.out.println(
    " a = " + binary[a]); 
    System.out.println(
    " b = " + binary); 
    System.out.println(
    " a|b = " + binary[c]); 
    System.out.println(
    " a&b = " + binary[d]); 
    System.out.println(
    " a^b = " + binary[e]); 
    System.out.println(
    "~a&b|a&~b = " + binary[f]); 
    System.out.println(
    " ~a = " + binary[g]); 


    }
     
    }
     



    在本例中,變量a與b對應位的組合代表了二進制數所有的 4 種組合模式:0-0,0-1,1-0 ,和1-1 。“|”運算符和“&”運算符分別對變量a與b各個對應位的運算得到了變量c和變量d的值。對變量e和f的賦值說明了“^”運算符的功能。字符串數組binary 代表了0到15 對應的二進制的值。在本例中,數組各元素的排列順序顯示了變量對應值的二進制代碼。數組之所以這樣構造是因為變量的值n對應的二進制代碼可以被正確的存儲在數組對應元素binary[n] 中。例如變量a的值為3,則它的二進制代碼對應地存儲在數組元素binary[3] 中。~a的值與數字0x0f (對應二進制為0000 1111 )進行按位與運算的目的是減小~a的值,保證變量g的結果小于16。因此該程序的運行結果可以用數組binary 對應的元素來表示。該程序的輸出如下:

    a = 0011 b = 0110 a|b = 0111 a&b = 0010 a^b = 0101 ~a&b|a&~b = 0101 ~a = 1100

    4.2.2 左移運算符
    左移運算符<<使指定值的所有位都左移規定的次數。它的通用格式如下所示:

    value << num
    這里,num 指定要移位值value 移動的位數。也就是,左移運算符<<使指定值的所有位都左移num位。每左移一個位,高階位都被移出(并且丟棄),并用0填充右邊。這意味著當左移的運算數是int 類型時,每移動1位它的第31位就要被移出并且丟棄;當左移的運算數是long 類型時,每移動1位它的第63位就要被移出并且丟棄。

    在對byte 和short類型的值進行移位運算時,你必須小心。因為你知道Java 在對表達式求值時,將自動把這些類型擴大為 int 型,而且,表達式的值也是int 型。對byte 和short類型的值進行移位運算的結果是int 型,而且如果左移不超過31位,原來對應各位的值也不會丟棄。但是,如果你對一個負的byte 或者short類型的值進行移位運算,它被擴大為int 型后,它的符號也被擴展。這樣,整數值結果的高位就會被1填充。因此,為了得到正確的結果,你就要舍棄得到結果的高位。這樣做的最簡單辦法是將結果轉換為byte 型。下面的程序說明了這一點:

    // Left shifting a byte value. 
    class ByteShift 


    public static void main(String args[]) 
    byte a = 64, b; 
    int i; 


    = a << 2
    = (byte) (a << 2); 


    System.out.println(
    "Original value of a: " + a); 
    System.out.println(
    "i and b: " + i + " " + b); 
    }
     
    }
     



    該程序產生的輸出下所示:

    Original value of a: 64
    i and b: 256 0


    因變量a在賦值表達式中,故被擴大為int 型,64(0100 0000 )被左移兩次生成值256 (10000 0000 )被賦給變量i。然而,經過左移后,變量b中惟一的1被移出,低位全部成了0,因此b的值也變成了0。

    既然每次左移都可以使原來的操作數翻倍,程序員們經常使用這個辦法來進行快速的2 的乘法。但是你要小心,如果你將1移進高階位(31或63位),那么該值將變為負值。下面的程序說明了這一點:

    // Left shifting as a quick way to multiply by 2. 
    class MultByTwo 


    public static void main(String args[]) 
    int i; 
    int num = 0xFFFFFFE


    for(i=0; i<4; i++
    num 
    = num << 1
    System.out.println(num); 


    }
     
    }
     



    這里,num 指定要移位值value 移動的位數。也就是,左移運算符<<使指定值的所有位都左移num位。每左移一個位,高階位都被移出(并且丟棄),并用0填充右邊。這意味著當左移的運算數是int 類型時,每移動1位它的第31位就要被移出并且丟棄;當左移的運算數是long 類型時,每移動1位它的第63位就要被移出并且丟棄。

    在對byte 和short類型的值進行移位運算時,你必須小心。因為你知道Java 在對表達式求值時,將自動把這些類型擴大為 int 型,而且,表達式的值也是int 型。對byte 和short類型的值進行移位運算的結果是int 型,而且如果左移不超過31位,原來對應各位的值也不會丟棄。但是,如果你對一個負的byte 或者short類型的值進行移位運算,它被擴大為int 型后,它的符號也被擴展。這樣,整數值結果的高位就會被1填充。因此,為了得到正確的結果,你就要舍棄得到結果的高位。這樣做的最簡單辦法是將結果轉換為byte 型。下面的程序說明了這一點:

    // Left shifting a byte value. 
    class ByteShift 


    public static void main(String args[]) 
    byte a = 64, b; 
    int i; 


    = a << 2
    = (byte) (a << 2); 


    System.out.println(
    "Original value of a: " + a); 
    System.out.println(
    "i and b: " + i + " " + b); 
    }
     
    }
     



    該程序產生的輸出下所示:

    Original value of a: 64
    i and b: 256 0


    因變量a在賦值表達式中,故被擴大為int 型,64(0100 0000 )被左移兩次生成值256 (10000 0000 )被賦給變量i。然而,經過左移后,變量b中惟一的1被移出,低位全部成了0,因此b的值也變成了0。

    既然每次左移都可以使原來的操作數翻倍,程序員們經常使用這個辦法來進行快速的2 的乘法。但是你要小心,如果你將1移進高階位(31或63位),那么該值將變為負值。下面的程序說明了這一點:

    // Left shifting as a quick way to multiply by 2. 
    class MultByTwo 


    public static void main(String args[]) 
    int i; 
    int num = 0xFFFFFFE


    for(i=0; i<4; i++
    num 
    = num << 1
    System.out.println(num); 


    }
     
    }
     
    }
     


    該程序的輸出如下所示:

    536870908
    1073741816
    2147483632
    -32


    初值經過仔細選擇,以便在左移 4 位后,它會產生-32。正如你看到的,當1被移進31 位時,數字被解釋為負值。

    4.2.3 右移運算符
    右移運算符>>使指定值的所有位都右移規定的次數。它的通用格式如下所示:

    value >> num

    這里,num 指定要移位值value 移動的位數。也就是,右移運算符>>使指定值的所有位都右移num位。下面的程序片段將值32右移2次,將結果8賦給變量a:

    int a = 32;
    a = a >> 2; // a now contains 8


    當值中的某些位被“移出”時,這些位的值將丟棄。例如,下面的程序片段將35右移2 次,它的2個低位被移出丟棄,也將結果8賦給變量a:

    int a = 35;
    a = a >> 2; // a still contains 8


    用二進制表示該過程可以更清楚地看到程序的運行過程:

    00100011 35
    >> 2
    00001000 8


    將值每右移一次,就相當于將該值除以2并且舍棄了余數。你可以利用這個特點將一個整數進行快速的2的除法。當然,你一定要確保你不會將該數原有的任何一位移出。

    右移時,被移走的最高位(最左邊的位)由原來最高位的數字補充。例如,如果要移走的值為負數,每一次右移都在左邊補1,如果要移走的值為正數,每一次右移都在左邊補0,這叫做符號位擴展(保留符號位)(sign extension ),在進行右移操作時用來保持負數的符號。例如,–8 >> 1 是–4,用二進制表示如下:

    11111000 –8 >>1 11111100 –4

    一個要注意的有趣問題是,由于符號位擴展(保留符號位)每次都會在高位補1,因此-1右移的結果總是–1。有時你不希望在右移時保留符號。例如,下面的例子將一個byte 型的值轉換為用十六
    進制表示。注意右移后的值與0x0f進行按位與運算,這樣可以舍棄任何的符號位擴展,以便得到的值可以作為定義數組的下標,從而得到對應數組元素代表的十六進制字符。

    // Masking sign extension. 
    class HexByte 
    static public void main(String args[]) 


    char hex[] = 
    0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’, 
    8’, ’9’, ’a’, ’b’, ’c’, ’d’, ’e’, ’f’’ 


    }

    byte b = (byte0xf1


    System.out.println(
    "b = 0x" + hex[(b >> 4& 0x0f+ hex[b & 0x0f]);}
    }
     



    該程序的輸出如下:

    b = 0xf1

    4.2.4 無符號右移
    正如上面剛剛看到的,每一次右移,>>運算符總是自動地用它的先前最高位的內容補它的最高位。這樣做保留了原值的符號。但有時這并不是我們想要的。例如,如果你進行移位操作的運算數不是數字值,你就不希望進行符號位擴展(保留符號位)。當你處理像素值或圖形時,這種情況是相當普遍的。在這種情況下,不管運算數的初值是什么,你希望移位后總是在高位(最左邊)補0。這就是人們所說的無符號移動(unsigned shift )。這時你可以使用Java 的無符號右移運算符>>> ,它總是在左邊補0。

    下面的程序段說明了無符號右移運算符>>> 。在本例中,變量a被賦值為-1,用二進制表示就是32位全是1。這個值然后被無符號右移24位,當然它忽略了符號位擴展,在它的左邊總是補0。這樣得到的值255被賦給變量a。

    int a = -1; a = a >>> 24;

    下面用二進制形式進一步說明該操作:

    11111111 11111111 11111111 11111111 int型-1的二進制代碼>>> 24 無符號右移24位00000000 00000000 00000000 11111111 int型255的二進制代碼

    由于無符號右移運算符>>> 只是對32位和64位的值有意義,所以它并不像你想象的那樣有用。因為你要記住,在表達式中過小的值總是被自動擴大為int 型。這意味著符號位擴展和移動總是發生在32位而不是8位或16位。這樣,對第7位以0開始的byte 型的值進行無符號移動是不可能的,因為在實際移動運算時,是對擴大后的32位值進行操作。下面的例子說明了這一點:

    // Unsigned shifting a byte value.
    class ByteUShift {
    static public void main(String args[]) {
    進制表示。注意右移后的值與0x0f進行按位與運算,這樣可以舍棄任何的符號位擴展,以便得到的值可以作為定義數組的下標,從而得到對應數組元素代表的十六進制字符。

    // Masking sign extension. 
    class HexByte 
    static public void main(String args[]) 


    char hex[] = 
    0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’, 
    8’, ’9’, ’a’, ’b’, ’c’, ’d’, ’e’, ’f’’ 


    }

    byte b = (byte0xf1


    System.out.println(
    "b = 0x" + hex[(b >> 4& 0x0f+ hex[b & 0x0f]);}
    }
     


    該程序的輸出如下:

    b = 0xf1

    4.2.4 無符號右移
    正如上面剛剛看到的,每一次右移,>>運算符總是自動地用它的先前最高位的內容補它的最高位。這樣做保留了原值的符號。但有時這并不是我們想要的。例如,如果你進行移位操作的運算數不是數字值,你就不希望進行符號位擴展(保留符號位)。當你處理像素值或圖形時,這種情況是相當普遍的。在這種情況下,不管運算數的初值是什么,你希望移位后總是在高位(最左邊)補0。這就是人們所說的無符號移動(unsigned shift )。這時你可以使用Java 的無符號右移運算符>>> ,它總是在左邊補0。

    下面的程序段說明了無符號右移運算符>>> 。在本例中,變量a被賦值為-1,用二進制表示就是32位全是1。這個值然后被無符號右移24位,當然它忽略了符號位擴展,在它的左邊總是補0。這樣得到的值255被賦給變量a。

    int a = -1; a = a >>> 24;

    下面用二進制形式進一步說明該操作:

    11111111 11111111 11111111 11111111 int型-1的二進制代碼>>> 24 無符號右移24位00000000 00000000 00000000 11111111 int型255的二進制代碼

    由于無符號右移運算符>>> 只是對32位和64位的值有意義,所以它并不像你想象的那樣有用。因為你要記住,在表達式中過小的值總是被自動擴大為int 型。這意味著符號位擴展和移動總是發生在32位而不是8位或16位。這樣,對第7位以0開始的byte 型的值進行無符號移動是不可能的,因為在實際移動運算時,是對擴大后的32位值進行操作。下面的例子說明了這一點:

    // Unsigned shifting a byte value. 
    class ByteUShift 
    static public void main(String args[]) 
    int b = 2
    int c = 3


    |= 4
    >>= 1
    <<= 1
    ^= c; 
    System.out.println(
    "a = " + a); 
    System.out.println(
    "b = " + b); 
    System.out.println(
    "c = " + c); 


    }
     
    }
     


    該程序的輸出如下所示:

    a = 3
    b = 1
    c = 6





    posted on 2007-12-28 18:48 々上善若水々 閱讀(1310) 評論(0)  編輯  收藏 所屬分類: J2SE

    主站蜘蛛池模板: 亚洲精品国自产拍在线观看| 未满十八私人高清免费影院| 亚洲区日韩区无码区| 青草草色A免费观看在线| 天黑黑影院在线观看视频高清免费 | 亚洲国产成人精品无码一区二区 | 在线综合亚洲欧洲综合网站 | 久久影院亚洲一区| 午夜网站免费版在线观看| 伊人久久免费视频| 中文字幕成人免费高清在线视频| 亚洲乱码国产乱码精品精| 免费观看无遮挡www的小视频| 中文无码亚洲精品字幕| 国产亚洲精品无码专区| 免费国产高清视频| 日韩在线免费电影| 91在线视频免费91| 夜夜爽妓女8888视频免费观看| 久久亚洲国产伦理| 亚洲精品你懂的在线观看| 亚洲高清最新av网站| 国产国产人免费人成免费视频| 国产一区二区三区免费观看在线| 亚洲中文无码av永久| 亚洲国产日韩一区高清在线| 亚洲Aⅴ无码专区在线观看q| 亚洲国产精品一区二区成人片国内 | 亚洲中文字幕乱码一区| 久久精品国产精品亚洲人人| 免费播放春色aⅴ视频| 国产成人精品男人免费| 免费鲁丝片一级观看| 日韩免费观看一区| 在线看亚洲十八禁网站| 精品国产亚洲AV麻豆 | 九九综合VA免费看| 免费毛片毛片网址| 国产精品亚洲专区在线观看| 亚洲综合色婷婷七月丁香| 亚洲人成色7777在线观看|