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

Java 開發之路(19):Long 緩存機制與 == 比較陷阱

     編輯:Java 綜合教學

Java 開發之路(19):Long 緩存機制與 == 比較陷阱

Long.valueOf() 在 [-128, 127] 範圍內返回緩存實例,超出範圍則新建對象。直接用 == 比較 Long 對象會導致邏輯錯誤,必須用 equals()。本文通過源碼剖析緩存實現,並給出最佳實踐建議。

現象演示

System.out.println(Long.valueOf(-129) == Long.valueOf(-129)); // false
System.out.println(Long.valueOf(-128) == Long.valueOf(-128)); // true
System.out.println(Long.valueOf(127) == Long.valueOf(127));   // true
System.out.println(Long.valueOf(128) == Long.valueOf(128));   // false

// 正確比較方式
System.out.println(Long.valueOf(128).equals(Long.valueOf(128))); // true

源碼深度剖析

Long.valueOf() 實現

public static Long valueOf(long l) {
    final int offset = 128;
    if (l >= -128 && l <= 127) { // 命中緩存區間
        return LongCache.cache[(int)l + offset];
    }
    return new Long(l); // 區間外新建對象
}

LongCache 靜態內部類

private static class LongCache {
    private LongCache() {}

    static final Long cache[] = new Long[-(-128) + 127 + 1]; // 長度 256

    static {
        for (int i = 0; i < cache.length; i++) {
            cache[i] = new Long(i - 128); // 預填充 -128 ~ 127
        }
    }
}

關鍵設計細節

  1. 緩存範圍固定:-128 ~ 127(含 0 共 256 個值),不可配置,源於 JVM 規範建議。
  2. offset 偏移量:128 使索引 0 → -128,128 → 0,255 → 127,正負數在數組中自然分界。
  3. 線程安全:靜態代碼塊在類加載階段單線程執行,天然安全;緩存數組不可變,讀取無鎖。
  4. 其他包裝類同理:Integer、Short、Byte、Character 均有類似緩存,範圍略有不同(Integer 同 -128~127,可通過 -XX:AutoBoxCacheMax 擴展)。

為什麼會有這個緩存?

  • 性能優化:小整數在業務邏輯中極高頻使用(索引、計數、狀態碼),緩存避免頻繁分配/回收對象,減輕 GC 壓力。
  • 內存節省:共享實例減少堆佔用。
  • 語義一致性:值相同的小整數共享實例,符合值類型直覺。

最佳實踐指南

場景錯誤寫法正確寫法說明
比較兩個 Long 值a == ba.equals(b) 或 Objects.equals(a, b)防 NPE,語義明確
比較 Long 與長整數longVal == Long.valueOf(100)longVal == 100L自動拆箱比較基本類型
集合去重/查找set.contains(Long.valueOf(id))set.contains(id) (id 為 long)避免裝箱產生新對象
作為 Map Keymap.put(Long.valueOf(id), val)map.put(id, val) (id 為 Long)直接用 Long 對象,equals/hashCode 正確

進階:自定義緩存範圍(僅 Integer 支援)

-XX:AutoBoxCacheMax=2000 // 啟動參數擴展 Integer 緩存上限至 2000
// Long 無對應參數,範圍固定不可變

總結

  • Long.valueOf() 在 [-128, 127] 返回共享實例,外部新建對象
  • 永遠不要用 == 比較包裝類對象,統一使用 equals()
  • 理解緩存機制有助於排查「明明值相等卻判斷不等」的詭異 Bug
  • 基本類型 long 比較用 ==,包裝類 Long 比較用 equals()
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved