Thinking in Java(2-3) 邏輯、位元與位移運算子
Java 的運算子是編寫高效程式的基石。本文將深入探討 Java 中的邏輯運算子、直接常數、位元運算子以及位移運算子,並透過實例來加深理解。
一、邏輯運算子(Logical Operators)
Java 中的邏輯運算子包括:
&&
(AND)||
(OR)!
(NOT)
這些運算子根據運算元的邏輯關係產生一個 boolean
值。
注意: 與 C/C++ 不同,Java 中不能直接將非 boolean
值用於邏輯表達式中,必須先使用關係運算子將其轉換為 boolean
。
常見錯誤示例
在 C++ 中,可以使用 while (node)
來替代 while (node != NULL)
,但在 Java 中,這樣的寫法會導致編譯錯誤。
// 常見錯誤
// C++ 中常使用 while (node) 簡寫 while (node != NULL)
// while (node) {} 在 Java中會報錯
while (node != null) {}
短路運算(Short-circuiting)
&&
(AND): 在condition1 && condition2
中,如果condition1
為false
,那麼整個表達式必定為false
,因此不會計算condition2
。||
(OR): 在condition1 || condition2
中,如果condition1
為true
,那麼整個表達式必定為true
,因此不會計算condition2
。
範例:
public class ShortCircuit {
static boolean test1(int val) {
print("test1(" + val + ")");
print("result: " + (val < 1));
return val < 1;
}
static boolean test2(int val) {
print("test2(" + val + ")");
print("result: " + (val < 2));
return val < 2;
}
static boolean test3(int val) {
print("test3(" + val + ")");
print("result: " + (val < 3));
return val < 3;
}
public static void main(String[] args) {
boolean b = test1(0) && test2(2) && test3(2);
print("expression is " + b);
}
} /* Output:
test1(0)
result: true
test2(2)
result: false
expression is false
*/
在上述程式中,test2(2)
返回 false
,使得整個表達式的結果為 false
,因此 test3(2)
不會被執行。
二、直接常數(Literals)
直接常數是在程式中直接使用的數值,編譯器通常可以根據上下文推斷出常數的資料型別。在有歧義的情況下,需要開發者明確指定資料型別。
範例:
public class Literals {
public static void main(String[] args) {
int i1 = 0x2f; // Hexadecimal (lowercase)
print("i1: " + Integer.toBinaryString(i1));
int i2 = 0X2F; // Hexadecimal (uppercase)
print("i2: " + Integer.toBinaryString(i2));
int i3 = 0177; // Octal (leading zero)
print("i3: " + Integer.toBinaryString(i3));
char c = 0xffff; // max char hex value
print("c: " + Integer.toBinaryString(c));
byte b = 0x7f; // max byte hex value
print("b: " + Integer.toBinaryString(b));
short s = 0x7fff; // max short hex value
print("s: " + Integer.toBinaryString(s));
long n1 = 200L; // long suffix
long n2 = 200l; // long suffix (but can be confusing)
long n3 = 200;
float f1 = 1;
float f2 = 1F; // float suffix
float f3 = 1f; // float suffix
double d1 = 1d; // double suffix
double d2 = 1D; // double suffix
// (Hex and Octal also work with long)
}
} /* Output:
i1: 101111
i2: 101111
i3: 1111111
c: 1111111111111111
b: 1111111
s: 111111111111111
*/
注意:
- 超出型別範圍的值會導致編譯錯誤。
- 若編譯器能夠自動識別型別,可以省略型別後綴。
指數表示法(Exponential Notation)
指數表示法用於表示非常大或非常小的數字,通常用於浮點數。
範例:
public class Exponents {
public static void main(String[] args) {
// Uppercase and lowercase 'e' are the same:
float expFloat = 1.39e-43f;
expFloat = 1.39E-43f;
System.out.println(expFloat);
double expDouble = 47e47d; // 'd' is optional
double expDouble2 = 47e47; // Automatically double
System.out.println(expDouble);
}
} /* Output:
1.39E-43
4.7E48
*/
說明:
e
或E
表示乘以 10 的多少次方,例如1.39e-43
表示 $1.39 \times 10^{-43}$。- 若未指定
f
或F
,則編譯器默認為double
型別。
三、位元運算子(Bitwise Operators)
Java 中的位元運算子主要用於對整數型別(如 int
和 long
)的二進位位元進行操作:
- XOR(異或):
^
- AND(與):
&
- OR(或):
|
- NOT(非):
~
範例:
// XOR: ^
// AND: &
// OR: |
// NOT: ~
// 定義變數
int a = 12; // 二進制表達為 1100
int b = 6; // 二進制表達為 0110
// XOR: ^ (異或)
int resultXor = a ^ b; // 結果是 10 (二進制為 1010)
// AND: & (與)
int resultAnd = a & b; // 結果是 4 (二進制為 0100)
// OR: | (或)
int resultOr = a | b; // 結果是 14 (二進制為 1110)
// NOT: ~ (非)
int resultNot = ~a; // 對 a 的每一位進行反轉
這些運算子也可以與指定運算子 =
結合使用,形成複合指定運算子,使程式更為簡潔:
a ^= b; // a 現在等於 10
a |= b; // a 現在等於 14
a &= b; // a 現在等於 4
注意:~
是一元運算子,不能與指定運算子=
結合使用。
四、位移運算子(Shift Operators)
Java 中的位移運算子用於對整數型別的數字進行二進位位元的移動:
- 左移:
<<
——將位元向左移動,低位補0
。 - 右移:
>>
——將位元向右移動,對於正數,高位補0
;對於負數,高位補1
。 - 無符號右移:
>>>
——無論正負,高位都補0
。
特點:
- 只能作用於整數型別。
- 可以與指定運算子結合使用,如
<<=
、>>=
、>>>=
。
位移操作可能導致的問題:
在執行位移操作時,byte
和 short
型別的數據會被自動提升為 int
型別,這可能會導致一些意外的結果。
範例:
public class URShift {
public static void main(String[] args) {
int i = -1;
print(Integer.toBinaryString(i));
i >>>= 10;
print(Integer.toBinaryString(i));
long l = -1;
print(Long.toBinaryString(l));
l >>>= 10;
print(Long.toBinaryString(l));
short s = -1;
print(Integer.toBinaryString(s));
s >>>= 10;
print(Integer.toBinaryString(s));
byte b = -1;
print(Integer.toBinaryString(b));
b >>>= 10;
print(Integer.toBinaryString(b));
b = -1;
print(Integer.toBinaryString(b));
print(Integer.toBinaryString(b>>>10));
}
} /* Output:
11111111111111111111111111111111
1111111111111111111111
1111111111111111111111111111111111111111111111111111111111111111
111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
11111111111111111111111111111111
1111111111111111111111
*/
解析:
- 對於
int
型別,-1
的二進位表示為全1
。 - 使用無符號右移
>>>
後,高位補0
,結果位元數減少。 - 對於
short
和byte
,在位移操作時被提升為int
,可能導致預期外的結果。
五、結論
透過本文的介紹,我們深入了解了 Java 中的邏輯運算子、直接常數、位元運算子和位移運算子。理解這些運算子的用法和特性,能夠幫助我們在開發中編寫出更高效、更健壯的程式。
Comments ()