不可變類的實例狀態創建後永不改變,天然適合多線程共享與跨組件傳遞。為減少內存佔用與 GC 壓力,應盡可能復用相同屬性值的實例。JDK 1.5 在 Integer 中引入實例緩存,正是這一模式的經典應用。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
默認緩存範圍 [-128, 127],可通過 -XX:AutoBoxCacheMax 擴大上限。對比 new Integer(10) 每次創建新對象,valueOf(10) 在緩存命中時返回同一引用,故 Integer.valueOf(10) == Integer.valueOf(10) 為 true,而 new Integer(10) == new Integer(10) 為 false。
使用 SoftReference 防止緩存佔用過多堆內存,JVM 在內存不足時可回收:
import java.util.*;
import java.lang.ref.SoftReference;
public final class Name {
private final String firstName;
private final String lastName;
// 緩存:鍵為 "firstName#lastName",值為 SoftReference
private static final Map> CACHE = new HashMap<>();
private Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public static Name valueOf(String firstName, String lastName) {
String key = firstName + "#" + lastName;
SoftReference ref = CACHE.get(key);
if (ref != null) {
Name cached = ref.get();
if (cached != null) return cached; // 緩存命中且未被回收
}
// 未命中或已被回收,創建新實例並放入緩存
Name created = new Name(firstName, lastName);
CACHE.put(key, new SoftReference<>(created));
return created;
}
// getter、equals/hashCode、toString 省略
}
並非所有不可變類都適合緩存,需同時滿足:
若實例種類無上限(如用戶輸入的任意字符串)或使用頻率低,緩存反而增加內存負擔與管理複雜度。
public 構造器與靜態工廠方法,讓調用方按需選擇Key 類ConcurrentHashMap + computeIfAbsent 或雙重檢查鎖