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
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); // 區間外新建對象
}
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
}
}
}
-128 ~ 127(含 0 共 256 個值),不可配置,源於 JVM 規範建議。128 使索引 0 → -128,128 → 0,255 → 127,正負數在數組中自然分界。Integer、Short、Byte、Character 均有類似緩存,範圍略有不同(Integer 同 -128~127,可通過 -XX:AutoBoxCacheMax 擴展)。| 場景 | 錯誤寫法 | 正確寫法 | 說明 |
|---|---|---|---|
| 比較兩個 Long 值 | a == b | a.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 Key | map.put(Long.valueOf(id), val) | map.put(id, val) (id 為 Long) | 直接用 Long 對象,equals/hashCode 正確 |
-XX:AutoBoxCacheMax=2000 // 啟動參數擴展 Integer 緩存上限至 2000
// Long 無對應參數,範圍固定不可變
Long.valueOf() 在 [-128, 127] 返回共享實例,外部新建對象== 比較包裝類對象,統一使用 equals()long 比較用 ==,包裝類 Long 比較用 equals()