题目
设计类型安全的异构容器并实现动态类型查询
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
泛型高级应用, 类型安全容器设计, 类型令牌模式, 泛型擦除补偿, 动态类型转换
快速回答
实现要点:
- 使用
Class<T>作为类型令牌键 - 通过
Map<Class<?>, Object>存储异构对象 - 利用泛型方法保证类型安全的存取:
public <T> void put(Class<T> type, T instance) - 实现动态类型查询:
public <T> Optional<T> find(Class<T> type) - 处理泛型擦除问题(如
List<String>.class非法)
问题背景
Java泛型通常用于固定元素类型的容器(如List<String>)。但在某些场景下,我们需要一个能存储任意类型对象且保持类型安全的容器,例如配置中心需要存储不同类型的配置项。
核心实现
import java.util.*;
public class TypeSafeContainer {
private final Map<Class<?>, Object> container = new HashMap<>();
// 类型安全地存入对象
public <T> void put(Class<T> type, T instance) {
container.put(Objects.requireNonNull(type), type.cast(instance));
}
// 直接获取对象(可能抛出ClassCastException)
public <T> T get(Class<T> type) {
return type.cast(container.get(type));
}
// 安全查询:返回Optional避免NPE
public <T> Optional<T> find(Class<T> type) {
return Optional.ofNullable(container.get(type))
.map(type::cast);
}
// 处理泛型类型(如List<String>)
public <T> void putGeneric(Key<T> key, T value) {
container.put(key, value);
}
public <T> T getGeneric(Key<T> key) {
return key.type.cast(container.get(key));
}
// 自定义键解决泛型擦除问题
public static class Key<T> {
private final Class<T> type;
private final String identifier;
public Key(Class<T> type, String identifier) {
this.type = type;
this.identifier = identifier;
}
@Override
public boolean equals(Object o) { /* 基于type和identifier实现 */ }
@Override
public int hashCode() { /* 基于type和identifier实现 */ }
}
}关键原理
- 类型令牌(Type Token):利用
Class<T>对象同时承载类型信息和运行时访问能力 - 类型安全守卫:
type.cast()在存取时进行动态类型检查 - 泛型擦除补偿:通过
Key<T>封装泛型类型信息,解决List<String>.class非法的问题
使用示例
TypeSafeContainer container = new TypeSafeContainer();
container.put(String.class, "Config Value");
container.put(Integer.class, 42);
// 安全获取
String s = container.get(String.class);
Optional<Integer> opt = container.find(Integer.class);
// 处理泛型类型
Key<List<String>> key = new Key<>(List.class, "stringList");
container.putGeneric(key, Arrays.asList("a", "b"));
List<String> list = container.getGeneric(key);最佳实践
- 优先使用
find()替代get()避免异常 - 为复杂泛型类型实现自定义
Key类 - 重写
Key的equals/hashCode确保唯一性 - 考虑线程安全场景使用
ConcurrentHashMap
常见错误
- 直接使用
Object转换(失去类型安全):// 错误示范! T value = (T) container.get(type); - 忽略
null处理导致NullPointerException - 尝试使用
List<String>.class(编译错误)
扩展知识
- Super Type Token:通过匿名类捕获泛型类型(Gson的
TypeToken实现原理) - 类型系统边界:容器无法区分
List<String>和List<Integer> - Java 14+:使用
Record简化Key类的实现