提示三十三

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));
}
上一篇下一篇

猜你喜欢

热点阅读