首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 移位運算符深度解析:<<、>>、>>> 的位級邏輯與陷阱

     編輯:Java 程式設計入門

核心概念:位運算的運算對象是二進制「位」

移位運算符僅適用於整數類型 (int, long, short, char, byte)。操作前,short/char/byte 自動提升為 int;long 保持 long。移位位數取右操作數低位:int 取低 5 位 (模 32),long 取低 6 位 (模 64),防止過度移位。

三大運算符語義對比

運算符名稱規則高位補充等效數學運算
<<左移向左移動 n 位,低位補 0低位補 0× 2ⁿ (無溢出時)
>>算術右移 (有符號)向右移動 n 位符號位擴展:正補 0,負補 1÷ 2ⁿ (向負無窮取整)
>>>邏輯右移 (無符號)向右移動 n 位無符號擴展:始終補 0無符號除以 2ⁿ

關鍵細節與常見坑

1. 負數右移的差異

int n = -1; // 0xFFFFFFFF
n >> 1  // 0xFFFFFFFF (仍為 -1,符號位擴展)
n >>> 1 // 0x7FFFFFFF (2147483647,高位補 0)

2. byte/short 進行 >>> 的陷阱 (Java 1.0/1.1 尤顯著)

byte b = -1; // 0xFF
b >>> 1; // 編譯時提升為 int (0xFFFFFFFF) → 邏輯右移 → 0x7FFFFFFF → 隱式收窄為 byte → 0xFF (-1) ❌
// 期望 0x7F (127) 但得到 -1
// 修正:(b & 0xFF) >>> 1 → 127 ✅

3. 復合賦值運算符

x <<= n  ≡  x = x << n
x >>= n  ≡  x = x >> n
x >>>= n ≡  x = x >>> n

實戰演示:所有位運算符效果可視化

下方代碼輸出 int 和 long 的二進制表示,驗證移位、按位與、或、異或、取反效果:

public class BitManipulation {
    public static void main(String[] args) {
        Random rand = new Random();
        int i = rand.nextInt();
        int j = rand.nextInt();

        pBinInt("-1", -1);
        pBinInt("+1", +1);
        pBinInt("MAX_INT", Integer.MAX_VALUE);  // 0x7FFFFFFF
        pBinInt("MIN_INT", Integer.MIN_VALUE);  // 0x80000000
        pBinInt("i", i);
        pBinInt("~i", ~i);
        pBinInt("-i", -i);
        pBinInt("j", j);
        pBinInt("i & j", i & j);
        pBinInt("i | j", i | j);
        pBinInt("i ^ j", i ^ j);
        pBinInt("i << 5", i << 5);
        pBinInt("i >> 5", i >> 5);
        pBinInt("(~i) >> 5", (~i) >> 5);
        pBinInt("i >>> 5", i >>> 5);
        pBinInt("(~i) >>> 5", (~i) >>> 5);

        // long 版同理,調用 pBinLong
    }

    static void pBinInt(String label, int val) {
        System.out.printf("%-12s int: %-12d binary: ", label, val);
        for (int b = 31; b >= 0; b--) System.out.print(((val >>> b) & 1) == 1 ? '1' : '0');
        System.out.println();
    }

    static void pBinLong(String label, long val) {
        System.out.printf("%-12s long: %-22d binary: ", label, val);
        for (int b = 63; b >= 0; b--) System.out.print(((val >>> b) & 1) == 1 ? '1' : '0');
        System.out.println();
    }
}

輸出片段解讀 (int 部分)

-1            int: -1            binary: 11111111111111111111111111111111
+1            int: 1             binary: 00000000000000000000000000000001
MAX_INT       int: 2147483647    binary: 01111111111111111111111111111111
MIN_INT       int: -2147483648   binary: 10000000000000000000000000000000
i             int: 59081716      binary: 00000011100001011000001111110100
~i            int: -59081717     binary: 11111100011110100111110000001011
-i            int: -59081716     binary: 11111100011110100111110000001100
i << 5        int: 1890614912    binary: 01110000101100000111111010000000
i >> 5        int: 1846303       binary: 00000000000111000010110000011111
i >>> 5       int: 1846303       binary: 00000000000111000010110000011111  (正數算術/邏輯右移同)
(~i) >> 5     int: -1846304      binary: 11111111111000111101001111100000  (負數算術右移補 1)
(~i) >>> 5    int: 132371424     binary: 00000111111000111101001111100000  (邏輯右移補 0)

核心觀察

  • 符號位 (最高位) 決定正負:0=正,1=負
  • ~i (按位取反) 等價於 -i - 1 (補碼定義)
  • -i = ~i + 1 (補碼求相反數)
  • 正數 >> 和 >>> 結果相同;負數截然不同
  • 二進制採用「有符號 2 的補碼」表示

最佳實踐建議

  1. **優先用無符號右移 >>>** 處理位掩碼、哈希、序列化等無符號邏輯。
  2. **避免對 byte/short 直接用 >>>**,先 & 0xFF 或 & 0xFFFF 擴展為 int 再移位。
  3. **移位位數取模特性**:i << 33 等價 i << 1 (33 % 32 = 1);long 模 64。
  4. **性能**:移位比乘除快,但現代 JIT 編譯器會自動優化 x * 2 → x << 1,代碼可讀性優先。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved