位移運算符是 Java 基礎中高頻考點、也是底層優化、加解密、網絡協議解析的常用工具。本文系統講解 `<<`(左移)、`>>`(有符號右移)、`>>>`(無符號右移)的二進制規則、正負數行為差異、等價數學運算、常見陷阱與實戰應用場景。
| 運算符 | 名稱 | 規則 | 符號位處理 | 等價數學運算 |
|---|---|---|---|---|
<< | 有符號左移 | 二進制整體左移 n 位,低位補 0 | 保持符號位參與移動(可能改變符號) | x * 2^n(無溢出時) |
>> | 有符號右移 | 二進制整體右移 n 位,高位補符號位 | 補符號位(正補 0,負補 1) | x / 2^n(向零取整) |
>>> | 無符號右移 | 二進制整體右移 n 位,高位補 0 | 忽略符號,高位固定補 0 | 無簡單等價(視為無符號整數除法) |
int x = 10; // 0000 0000 0000 0000 0000 0000 0000 1010 int x2 = x << 2; // 0000 0000 0000 0000 0000 0000 0010 1000 = 40 // 10 * 2^2 = 40 // 負數左移 int y = -10; // 1111 1111 1111 1111 1111 1111 1111 0110 (補碼) int y2 = y << 2; // 1111 1111 1111 1111 1111 1111 1101 1000 = -40 // 負數左移 n 位 ≈ -( |x| * 2^n ),但可能溢出改變符號
int x = 10; // 0000...1010 int x2 = x >> 2; // 0000...0010 = 2 (10 / 4 = 2.5 -> 2) // 負數右移 int y = -10; // 1111...0110 int y2 = y >> 2; // 1111...1101 = -3 // 規律:偶數負數 /2^n 向零取整;奇數負數 /2^n 向零取整再 -1 // -10 / 4 = -2.5 -> 向零取整 -2 -> 但結果是 -3(因補碼特性) // 通用公式:x >> n 等價於 floor(x / 2^n) 對負數向下取整
int x = 10; int x2 = x >>> 2; // 同 >>,結果 2 int y = -10; // 1111...0110 (32 位) int y2 = y >>> 2; // 0011...1101 = 1073741821 // 高位補 0,負數變大正數!此操作視 int 為無符號 32 位整數
Java 規定:int 移位位數取模 32,long 取模 64。
10 << 34 == 10 << (34 % 32) == 10 << 2 == 40 10 >> 34 == 10 >> 2 == 2 -10 >>> 34 == -10 >>> 2 == 1073741821
int pageSize = 1 << 10; // 1024,替代 1024 int index = offset >> 10; // offset / 1024 int remainder = offset & 1023; // offset % 1024 (位與操作)
int argb = 0xFFCC9966; int a = (argb >> 24) & 0xFF; // 255 int r = (argb >> 16) & 0xFF; // 204 int g = (argb >> 8) & 0xFF; // 153 int b = argb & 0xFF; // 102
int READ = 1 << 0; // 0001 int WRITE = 1 << 1; // 0010 int EXECUTE = 1 << 2; // 0100 int perm = READ | WRITE; // 0011 = 3 boolean canRead = (perm & READ) != 0; perm |= EXECUTE; // 添加執行權限 perm &= ~WRITE; // 移除寫入權限
int mid = (low + high) >>> 1; // 無符號右移等價於 (low+high)/2 但不溢出 // 或 int mid = low + ((high - low) >> 1);
// 狀態高 16 位存讀計數,低 16 位存寫計數 static final int SHARED_SHIFT = 16; int readCount = state >>> SHARED_SHIFT; // 無符號右移取高位 int writeCount = state & 0xFFFF; // 位與取低位 // 讀鎖獲取:state + (1 << 16) // 寫鎖獲取:state + 1
| 陷阱 | 說明 | 正確做法 |
|---|---|---|
| 負數右移期望正數 | -10 >> 1 == -5,非 5 | 需正數用 >>> 或先取絕對值 |
| 左移溢出改變符號 | 1 << 31 == -2147483648 | 用 long 或 BigInteger 避免溢出 |
| byte/short 自動提升 | byte b = 1; b << 1 先提升為 int 再移位 | 結果需強轉 (byte)(b << 1) |
| 移位位數為負 | 編譯錯誤 | 確保位數 >= 0 |
| 混淆 >> 和 >>> | 負數行為截然不同 | 記住:>> 保符號,>>> 不保符號 |
<<:乘 2^n,低位補 0,可能溢出改符號。>>:除 2^n(算術右移),高位補符號位,負數向下取整。>>>:邏輯右移,高位補 0,負數變大正數,視為無符號數。熟練掌握位移運算,能寫出更高效、更底層的 Java 代碼,也是面試必考核心知識點。