提示三十三
2022-07-19 本文已影响0人
飞絮搅青冥
提示三十三:考虑类型安全的异构容器
泛型常用于集合,被充当被参数化了的容器,这样就限制了每个容器都只能有固定个数的参数。将键参数化,而不是容器,可以突破这种限制。书中举例说明如果安全的操作:
public class Favorites {
private Map<Class<?>, Object> favorites = new HashMap<>();
public <T> void putFavorite(Class<T> type, T instance) {
favorites.put(Objects.requireNonNull(type), instance);
}
public <T> T getFavorite(Class<T> type) {
return type.cast(favorites.get(type));
}
}
但是恶意使用原始形式的类对象,从而很容易破坏 类型安全性。为了确保类型安全,可以在插入数据时进行动态转换。
public <T> void putFavorite(Class<T> type, T instance) {
favorites.put(type, type.cast(instance));
}
cast我也经常使用,在stream中用.stream().filter(T.class::isInstance).map(T.class::cast)
可以方便的进行对象的转化。
第二个限制是不能用于不可具体化的类型。比如:
Favorites favorites = new Favorites();
favorites.putFavorite(List.class, Arrays.asList("123"));
favorites.putFavorite(List.class, Arrays.asList(12));
System.out.println(favorites.getFavorite(List.class));
List<Integer> 和List<String> 共用一个Class对象,可能会导致后续处理出现无法预计的结果。
最后书中还提到可以利用 asSubclass方法把类Class<?>的对象强制转换成 Class<? extends Annotation>。这个在自定义注解的时候可能有用,正好注解这一块知识我也没有掌握的很好,有空可以好好研究研究。
static Annotation getAnnotation(AnnotatedElement element, String annotationTypeName) {
Class<?> annotationType = null; // Unbounded type token
try {
annotationType = Class.forName(annotationTypeName);
} catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
return element.getAnnotation(annotationType.asSubclass(Annotation.class));
}