類 A 調用 entity.setValue("x"),類 B new Entity().getValue() 取到 null。
原因:new Entity() 創建的是新對象,堆內存不同地址,字段默認值為 null。
public class Entity {
public static String value; // 靜態字段屬於類,所有實例共享
}
✅ 能「跨類取值」 | ❌ **嚴重缺陷**:線程不安全、全局狀態污染、單元測試困難、無法區分不同業務上下文(如多用戶並發會互相覆蓋)。
// 1. 定義為 Spring Bean (默認單例)
@Component
public class Entity {
private String value;
// getter/setter
}
// 2. 類 A 和類 B 都注入同一 Entity 實例
@Service
public class ClassA {
@Autowired private Entity entity;
public void setData() { entity.setValue("x"); }
}
@Service
public class ClassB {
@Autowired private Entity entity; // 同一實例!
public String getData() { return entity.getValue(); } // 返回 "x"
}
核心:**容器管理生命周期,保證注入點引用同一對象**。
public class Main {
public static void main(String[] args) {
Entity shared = new Entity(); // 唯一實例
ClassA a = new ClassA(shared); // 構造器注入
ClassB b = new ClassB(shared);
a.setData();
System.out.println(b.getData()); // "x"
}
}
class ClassA {
private Entity entity;
public ClassA(Entity e) { this.entity = e; }
public void setData() { entity.setValue("x"); }
}
class ClassB {
private Entity entity;
public ClassB(Entity e) { this.entity = e; }
public String getData() { return entity.getValue(); }
}
public class Entity {
private static volatile Entity instance;
private String value;
private Entity() {}
public static Entity getInstance() {
if (instance == null) synchronized (Entity.class) { if (instance == null) instance = new Entity(); }
return instance;
}
// getter/setter
}
// 使用
Entity.getInstance().setValue("x");
Entity.getInstance().getValue(); // "x"
⚠️ 本質是全局狀態,難以測試、擴展,僅適合真正的「全局唯一資源」(如配置管理器)。
public class ContextHolder {
private static final ThreadLocal holder = new ThreadLocal<>();
public static void set(Entity e) { holder.set(e); }
public static Entity get() { return holder.get(); }
public static void clear() { holder.remove(); }
}
// 請求處理線程中
ContextHolder.set(new Entity("request-data"));
// 同線程任意深度調用
Entity e = ContextHolder.get();
適用:Web 請求上下文傳遞(用戶信息、事務ID、鏈路追蹤ID)。
| 場景 | 推薦方案 | 關鍵點 |
|---|---|---|
| Spring/Spring Boot 項目 | 依賴注入 (@Autowired) | 容器管理單例 Bean,最規範 |
| 普通 Java SE / Android 早期 | 構造器/方法傳遞引用 | 顯式依賴,無隱式全局狀態 |
| Web 請求上下文數據 | ThreadLocal / RequestContextHolder | 線程隔離,請求結束自動清理 |
| 真正全局唯一資源 (配置、連接池) | 單例模式 / 枚舉單例 | 雙重檢查鎖或枚舉實現線程安全 |
new 出新對象自然拿不到舊值。核心解法是讓多處代碼持有同一對象引用。首選依賴注入(框架環境)或顯式傳遞引用(無框架),避免濫用 static 單例 導致耦合與測試噩夢。