题目
设计一个类型安全的异构容器
信息
- 类型:问答
- 难度:⭐⭐
考点
泛型应用,类型安全,类型令牌
快速回答
通过泛型实现一个可存储多种类型对象的容器:
- 使用
Class<T>作为键保证类型安全 - 通过
put方法存储对象时绑定类型信息 - 通过
get方法获取对象时进行动态类型检查 - 利用
Class.cast()实现安全的类型转换
问题背景
常规容器(如Map<K, V>)只能存储单一类型元素。实际场景中可能需要存储多种类型对象(如配置中心需存储String、Integer等不同类型配置值),同时保证类型安全。
解决方案
public class TypeSafeContainer {
private Map<Class<?>, Object> container = new HashMap<>();
public <T> void put(Class<T> type, T instance) {
container.put(Objects.requireNonNull(type), instance);
}
public <T> T get(Class<T> type) {
return type.cast(container.get(type));
}
}核心原理
- 类型令牌(Type Token):利用
Class<T>对象携带泛型类型信息 - 类型安全:
put方法通过泛型参数约束键值类型一致性 - 动态转换:
get方法使用Class.cast()实现运行时类型检查
使用示例
TypeSafeContainer container = new TypeSafeContainer();
container.put(String.class, "Config Value");
container.put(Integer.class, 42);
String s = container.get(String.class); // 正确
Integer i = container.get(Integer.class); // 正确
Double d = container.get(Double.class); // 返回null
String error = container.get(Integer.class); // ClassCastException最佳实践
- 优先使用
Class.cast()而非强制转换,提供更好的类型安全 - 对
null值做防御性处理(如示例中的Objects.requireNonNull) - 考虑线程安全场景可使用
ConcurrentHashMap
常见错误
- 原始类型问题:
container.put(int.class, 1)会导致自动装箱,实际存储 - 子类类型问题:
container.put(Number.class, 1)后get(Integer.class)返回null - 通配符误用:错误使用
Class<?>作为键会破坏类型安全
扩展知识
- Super Type Token:解决泛型类型擦除问题(如存储
List<String>)TypeReference<List<String>> token = new TypeReference<>(){}; // 通过token.getType()获取完整泛型类型 - 类型安全限制:无法用于重载方法(类型擦除后方法签名相同)
- Java 8+优化:使用
computeIfAbsent实现延迟初始化