代码之家  ›  专栏  ›  技术社区  ›  Glains

使用泛型类型参数存储对类的引用,并使用同一个泛型类型参数存储对类的实现

  •  0
  • Glains  · 技术社区  · 6 年前

    我用的是 Map 要存储对泛型类型参数的类和具有相同泛型类型参数的实现对象的引用,更具体地说:

    public class SomeImpl<T extends BaseClass> {
    
        void execute(T instance);
    }
    

    现在,在另一个类中,我想基于它们的泛型类型参数存储对实现的引用。

    private Map<Class<BaseClass>, SomeImpl<BaseClass>> map;
    

    但是,我发现在这里操作泛型有些混乱,特别是因为显示了很多不安全的强制转换警告。

    private <T extends BaseClass> void register(SomeImpl<T> impl, Class<T> aClass) {
        // unsafe
        Class<BaseClass> configClass = (Class<BaseClass>) aClass; 
        // unsafe
        map.put((SomeImpl<BaseClass>) impl, configClass);
    }
    

    稍后当我想要检索某个实例时

    private SomeImpl<BaseClass> get(Class<? extends BaseClass> aClass) {
        // unsafe
        return (SomeImpl<BaseClass>) map.get(aClass); 
    }
    

    如果上述声明是安全的,那么可以安全地忽略这些警告吗?

    1 回复  |  直到 6 年前
        1
  •  0
  •   Glains    6 年前

    最后,我确实采用了以下解决方案。非常感谢Radiodef,他告诉我使用类型安全的异构容器。

    private Map<Class<?>, SomeImpl<?>> map = new HashMap<>();
    

    具体实现方法如下:

    public <T extends BaseClass> void addImpl(SomeImpl<T> loader, Class<T> aClass) {
        map.put(type, loader);
    }
    
    public <T extends BaseClass> SomeImpl<T> getImpl(Class<T> aClass) {
        return (SomeImpl<T>) map.get(type);
    }
    

    最初,我也在寻找一个可以用 BaseClass . 我发现这是不可能的,所以下面的技巧:

    public SomeImpl<BaseClass> getBaseImpl(Class<? extends BaseClass> aClass) {
        return (BaseLoader<BaseClass>) map.get(type);
    }
    

    这确实是一个未保存的转换,因为编译器无法确保 基类 通过了。但是,我可以确保始终传递正确的类型(或者强制使用 isAssignableFrom ).

    这让我可以装一些 基类 对象,来自数据库,例如:

    List<BaseClass> list = getSomeBaseClasses();
    
    Map<Class<? extends BaseClass>, List<BaseClass> map = list.stream()
        .collect(Collectors.groupingBy(BaseClass::getClass));
    
    map.forEach((aClass, bases) -> {
        SomeImpl<BaseClass> impl = getBaseImpl(aClass);
        impls.forEach(impl::execute);
    }