JAVA中有關byte,int,long這些基本數據類型的存儲方式以及負數在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 位邏輯運算符的結果 
A 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 ~A 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 = (~a & b) | (a & ~b); 
int g = ~a & 0x0f; 


System.out.println(" a = " + binary[a]); 
System.out.println(" b = " + binary[b]); 
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; 


i = a << 2; 
b = (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; 


i = a << 2; 
b = (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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章