位移運算符是 Java 中直接操作二進位位元的高效工具,廣泛應用於效能優化、加密演算法、網路協議解析等場景。本文系統講解三種位移運算符的原理、特性與實戰應用。
| 運算符 | 名稱 | 規則 | 等價數學運算 | 適用類型 |
|---|---|---|---|---|
<< | 左移 | 高位捨棄,低位補 0 | × 2n(溢位截斷) | byte/short/char/int/long |
>> | 有符號右移 | 低位捨棄,高位補符號位 | ÷ 2n(向下取整) | byte/short/char/int/long |
>>> | 無符號右移 | 低位捨棄,高位補0 | 無符號整數 ÷ 2n | byte/short/char/int/long |
<<int a = 16; // 二進位:0000 0000 0000 0000 0000 0000 0001 0000 int b = a << 2; // 二進位:0000 0000 0000 0000 0000 0000 0100 0000 = 64 // 16 × 2² = 64
>>(保持符號)int a = 16; // 0000 ... 0001 0000 int b = a >> 2; // 0000 ... 0000 0100 = 4 // 16 ÷ 2² = 4 int c = -16; // 1111 ... 1111 0000 (補碼) int d = c >> 2; // 1111 ... 1111 1100 = -4 // -16 ÷ 2² = -4(向負無窮大取整)
>>>(忽略符號)int c = -16; // 1111 1111 1111 1111 1111 1111 1111 0000 int e = c >>> 2; // 0011 1111 1111 1111 1111 1111 1111 1100 = 1073741820 // 視為無符號整數 4294967280 ÷ 4 = 1073741820
public class ShiftOperatorDemo {
public static void main(String[] args) {
int a = 16;
int b = a << 2; // 左移 2 位
int c = a >> 2; // 有符號右移 2 位
int d = a >>> 2; // 無符號右移 2 位(正數時與 >> 相同)
System.out.println("=== 正數 16 ===");
printBinary("a (16)", a);
printBinary("a << 2", b);
printBinary("a >> 2", c);
printBinary("a >>> 2", d);
System.out.println("a << 2 = " + b + " (16 * 4)");
System.out.println("a >> 2 = " + c + " (16 / 4)");
System.out.println("a >>> 2 = " + d);
System.out.println("\n=== 負數 -16 ===");
int neg = -16;
printBinary("neg (-16)", neg);
printBinary("neg >> 2", neg >> 2);
printBinary("neg >>> 2", neg >>> 2);
System.out.println("neg >> 2 = " + (neg >> 2) + " (保持負號,算術右移)");
System.out.println("neg >>> 2 = " + (neg >>> 2) + " (符號位補 0,邏輯右移)");
System.out.println("\n=== 邊界測試 ===");
// int 32 位,移位 32 相當於移位 0 (32 % 32 = 0)
System.out.println("16 << 32 = " + (16 << 32)); // 16
System.out.println("16 >> 33 = " + (16 >> 33)); // 0 (16 >> 1)
// long 64 位,移位模 64
long l = 16L;
System.out.println("16L << 64 = " + (l << 64)); // 16
}
static void printBinary(String label, int value) {
System.out.printf("%-12s: %32s%n", label,
Integer.toBinaryString(value).replace(' ', '0'));
}
}
=== 正數 16 === a (16) : 10000 a << 2 : 1000000 a >> 2 : 100 a >>> 2 : 100 a << 2 = 64 (16 * 4) a >> 2 = 4 (16 / 4) a >>> 2 = 4 === 負數 -16 === neg (-16) : 11111111111111111111111111110000 neg >> 2 : 11111111111111111111111111111100 neg >>> 2 : 00111111111111111111111111111100 neg >> 2 = -4 (保持負號,算術右移) neg >>> 2 = 1073741820 (符號位補 0,邏輯右移) === 邊界測試 === 16 << 32 = 16 16 >> 33 = 0 16L << 64 = 16
n % 32n % 6416 << 32 == 16、16 >> 33 == 16 >> 1 == 8byte b = 10; b = b << 2; // 編譯錯誤!int 無法隱式轉 byte b = (byte) (b << 2); // 需強制轉型 // 所有位移運算先提升至 int 或 long 再運算 short s = 10; int result = s << 2; // 正常,結果為 int
>>>> 將操作數視為無符號數處理>> 和 >>>> 結果相同// 編譯器優化會自動轉換,但手寫更明確 int multiplyBy8 = x << 3; // x * 8 int divideBy4 = x >> 2; // x / 4 (正數) int divideBy4Unsigned = x >>> 2; // 無符號除法
// 定義標誌位 static final int FLAG_READ = 1 << 0; // 0001 static final int FLAG_WRITE = 1 << 1; // 0010 static final int FLAG_EXEC = 1 << 2; // 0100 // 設定標誌 int permissions = FLAG_READ | FLAG_WRITE; // 0011 = 3 // 檢查標誌 boolean canRead = (permissions & FLAG_READ) != 0; // 清除標誌 permissions &= ~FLAG_WRITE; // 0001
int argb = 0xFF804020; // Alpha=255, Red=128, Green=64, Blue=32 int alpha = (argb >> 24) & 0xFF; // 255 int red = (argb >> 16) & 0xFF; // 128 int green = (argb >> 8) & 0xFF; // 64 int blue = argb & 0xFF; // 32
// 錯誤:(low + high) / 2 可能溢位 // 正確:low + ((high - low) >> 1) int mid = low + ((high - low) >> 1); // 或無符號版本(Java 8+) int mid = (low + high) >>> 1;
// n > 0 且 n & (n-1) == 0 boolean isPowerOfTwo = (n > 0) && ((n & (n - 1)) == 0);
| 項目 | 說明 |
|---|---|
| 效能 | CPU 指令級操作,極快,現代 JVM 會優化乘除為位移 |
| 溢位 | 左移可能導致資料遺失(高位捨棄),無異常拋出 |
| 負數除法 | >> 向負無窮大取整,/ 向零取整,結果不同 |
| 可讀性 | 業務邏輯優先用 *//,位運算加註解說明意圖 |
位移運算符是貼近硬體的高效工具,掌握其符號位處理差異、移位取模規則、類型提升機制,能在效能敏感場景、位元級資料處理、演算法優化中發揮關鍵作用。實戰中建議:核心邏輯加註解、邊界條件寫測試、優先可讀性。