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

Java 整數緩存陷阱:== 比較 Integer 的經典坑與源碼深度解析

     編輯:Java 相關知識

現象:令人困惑的比較結果

public static void main(String[] args) {
    Integer p = 10000;
    Integer q = 10000;
    System.out.println(p == q);      // false ❌
    System.out.println(p.equals(q)); // true  ✅
}

結論:比較包裝類數值必須使用 equals(),絕不可用 ==。

源碼深度解析:IntegerCache 機制

JDK 源碼 java.lang.Integer.IntegerCache 靜態內部類:

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        int h = 127;
        String prop = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (prop != null) {
            try {
                int i = Integer.parseInt(prop);
                i = Math.max(i, 127);
                h = Math.min(i, Integer.MAX_VALUE - (-low) - 1);
            } catch (NumberFormatException ignored) {}
        }
        high = h;
        cache = new Integer[(high - low) + 1];
        for (int k = 0, j = low; k < cache.length; k++) {
            cache[k] = new Integer(j++);
        }
        // [-128, 127] 必須緩存 (JLS 5.1.7)
        assert high >= 127;
    }
    private IntegerCache() {}
}

核心機制解讀

  1. 緩存範圍:默認 [-128, 127],可通過 -XX:AutoBoxCacheMax=<size> 調整上限
  2. 類加載時預創建:靜態代碼塊在類初始化時創建所有緩存對象
  3. valueOf() 走緩存:
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
  4. 自動裝箱調用 valueOf():Integer p = 10000; 等價於 Integer p = Integer.valueOf(10000);

為什麼 10000 會失敗?

  • 10000 超出默認緩存範圍 [-128, 127]
  • 每次自動裝箱都調用 new Integer(10000) 創建新對象
  • == 比較引用地址,自然為 false

驗證緩存行為

Integer a = 100;  // 緩存範圍內
Integer b = 100;
System.out.println(a == b); // true ✅ (同一緩存對象)

Integer c = 200;  // 緩存範圍外
Integer d = 200;
System.out.println(c == d); // false ❌ (不同對象)

其他包裝類同樣機制

類型緩存範圍配置參數
Byte全範圍 [-128, 127] (全部緩存)無
Short[-128, 127]-XX:AutoBoxCacheMax
Long[-128, 127]-XX:AutoBoxCacheMax
Character[\u0000, \u007F] (0-127)無
Integer[-128, 127]-XX:AutoBoxCacheMax

注意:Float、Double 不緩存,每次裝箱必創建新對象。

最佳實踐指南

  1. 比較數值永遠用 equals():p.equals(q)
  2. 基本類型優先:能用 int 別用 Integer,避免裝箱拆箱開銷與陷阱
  3. 明確語義:需要引用語義(如可為 null、作為 Map Key)才用包裝類
  4. 調優緩存:高頻使用特定大整數場景可調大 AutoBoxCacheMax

總結

Integer 緩存機制是 JVM 優化自動裝箱性能的設計,但也引入了引用比較與值比較語義不一致的經典陷阱。理解緩存範圍、valueOf() 語義、自動裝箱行為,堅持「值比較用 equals,引用比較用 ==」,是避坑關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved