現象
long x = 0xFFFFFFFFFFFFFFFFL; // 16個F
System.out.println(x); // 輸出 -1
核心原理:補碼表示法
Java 基本類型(byte/short/int/long)均採用**補碼**表示有符號整數。
以 4 位為例(擴展至 64 位同理)
| 二進制 | 無符號值 | 補碼有符號值 | 說明 |
| 0000 | 0 | 0 | |
| 0001 | 1 | 1 | |
| 0111 | 7 | 7 | 最大正數 |
| 1000 | 8 | -8 | 最小負數 |
| 1001 | 9 | -7 | |
| 1110 | 14 | -2 | |
| 1111 | 15 | -1 | 全 1 表示 -1 |
為什麼全 1 是 -1?
補碼定義:負數 = 2^n - 絕對值 (n 為位數)
- 4位:-1 = 16 - 1 = 15 = 1111₂
- 64位:-1 = 2^64 - 1 = 18446744073709551615 = 0xFFFFFFFFFFFFFFFF
另一種理解:**模 2^n 同餘**。在模 16 意義下,15 ≡ -1。計算機定長存儲天然實現模運算。
推廣:0xFFFFFFFFFFFFFFFE = -2
1110 (二進制) = 14 (無符號) = -2 (補碼)
// 驗證:-2 + 2 = 0
1110 (-2)
+ 0010 ( 2)
= 10000 → 截斷高位 → 0000 (0) ✓
Java 代碼驗證
public class OverflowDemo {
public static void main(String[] args) {
long max = Long.MAX_VALUE; // 0x7FFFFFFFFFFFFFFF = 9223372036854775807
long min = Long.MIN_VALUE; // 0x8000000000000000 = -9223372036854775808
System.out.println("max = " + max);
System.out.println("max + 1 = " + (max + 1)); // 溢出變為 min
System.out.println("min - 1 = " + (min - 1)); // 溢出變為 max
// 位運算視角
System.out.println("~0L = " + (~0L)); // -1
System.out.println("~0L >>> 1 = " + (~0L >>> 1)); // 無符號右移
}
}
關鍵結論
- 補碼將「減法」轉化為「加法」:`a - b = a + (~b + 1)`
- 符號位為 1 表示負數,但**數值由所有位共同決定**
- Java 無無符號類型(除 `char`),所有整型運算均為補碼有符號運算
- 溢出**不拋異常**,按模 2^n 環狀截斷,需開發者自行檢查(如 `Math.addExact`)
- 上一篇文章: C語言圖形界面開發選擇:控制台模擬、Windows API、MFC與Qt對比
- 下一篇文章: 解決 window.location.href 參數在瀏覽器地址欄消失的問題
Copyright ©
程式碼之家 All Rights Reserved