普通 Map<String, Object> 存取值時需強制轉型,且無法編譯期檢查類型匹配:
Map<String, Object> map = new HashMap<>();
map.put("key", runnable);
Executor executor = (Executor) map.get("key"); // 運行時 ClassCastException
Joshua Bloch 在《Effective Java》第 29 條提出 類型安全異構容器 模式,利用泛型將類型信息綁定到 Key 上,實現編譯期類型安全。
Class<T> 是泛型化的,可作為攜帶類型信息的 Key:
public class Context {
private final Map<Class<?>, Object> values = new HashMap<>();
public <T> void put(Class<T> key, T value) {
values.put(key, value);
}
public <T> T get(Class<T> key) {
return key.cast(values.get(key)); // 動態轉型,類型安全
}
}
Context ctx = new Context();
ctx.put(Runnable.class, () -> System.out.println("run"));
ctx.put(Executor.class, Runnable::run);
Runnable r = ctx.get(Runnable.class); // 編譯期類型安全
Executor e = ctx.get(Executor.class); // 不會混淆
// Runnable r2 = ctx.get(Executor.class); // 編譯報錯!
若需存儲多個 Runnable,引入帶標識符的 Key:
public class Key<T> {
private final String identifier;
private final Class<T> type;
public Key(String identifier, Class<T> type) {
this.identifier = identifier;
this.type = type;
}
// 必須重寫 equals/hashCode,否則 Map 查找失效
@Override public boolean equals(Object o) { ... }
@Override public int hashCode() { ... }
}
public class Context {
private final Map<Key<?>, Object> values = new HashMap<>();
public <T> void put(Key<T> key, T value) {
values.put(key, value);
}
public <T> T get(Key<T> key) {
return key.type.cast(values.get(key));
}
}
public static <T> Key<T> key(String id, Class<T> type) {
return new Key<>(id, type);
}
// 使用
Context ctx = new Context();
ctx.put(key("task1", Runnable.class), () -> System.out.println("task1"));
ctx.put(key("task2", Runnable.class), () -> System.out.println("task2"));
Runnable t1 = ctx.get(key("task1", Runnable.class)); // 精確獲取
ctx.put((Class) Runnable.class, "not a Runnable")。put 方法內部做 key.cast(value) 防禦性檢查。List<String>、Map<Integer, String> 等泛型類型。Class 對象(List.class)。TypeReference(Gson/Jackson 風格)緩解。BeanFactory 獲取 Bean:getBean(Class<T> requiredType)cache.get(key, User.class)類型安全異構容器模式將「類型參數從容器移至鍵上」,巧妙繞過 Java 泛型擦除限制。核心技巧:
Class<T> 或自定義 Key<T> 攜帶類型信息Class.cast() 替代強制轉型,實現動態類型檢查這是 Java 泛型進階應用的經典案例,深刻理解後能設計出更優雅、類型安全的 API。