创建一个值为泛型类型的地图,并能够在从地图中检索后对值进行操作

时间:2018-05-02 08:20:07

标签: java generics

有类存储库

public class Repository<T> {


    public void add(T t){

    }
}

另一类RepoHolder定义为

public class RepoHolder {


    private Map<String, Repository<?>> repoMap = new HashMap<String, Repository<?>>();

    public Repository<?> getRepo(String type){  
        return repoMap.get(type);
    }


    public void registerRepo(String repoType,Repository<?> repo){
        repoMap.put(repoType, repo);
    }

}

我想执行以下操作:

    Repository<String> repo = new Repository<String>();
    holder.registerRepo("mykey", repo);
    Repository<?> repo1 = holder.getRepo("mykey");
    //below doesn't compile
                repo1.add("fdfd");

上面的代码片段没有编译。我怎样才能实现这个用例?

2 个答案:

答案 0 :(得分:2)

这些行:

Repository<?> repo1 = holder.getRepo("mykey");
repo1.add("fdfd");

显然不是类型正确的:你试图将String放入一些你不知道参数类型应该是什么的东西。它可以Repository<String>,但也可以是Repository<Integer>(或Repository<AnythingElse>)。

这里的“明显”解决方法是使getRepo通用:

public <T> Repository<T> getRepo(String type){  
    return (Repository<T>) repoMap.get(type);
}

因为那时你可以写:

Repository<String> repo1 = holder.getRepo("mykey");
repo1.add("fdfd");

不要,因为你可以同样写

Repository<Integer> repo1 = holder.getRepo("mykey");
repo1.add(123);

它会在运行时失败。

您需要一些方法将类型与回购关联起来。

例如,您可以将其他参数传递给getRepo

public <T> Repository<T> getRepo(String type, Class<T> clazz)

然后在该方法中添加逻辑,以确保type标识的存储库实际上是“Repository<clazz>”的实例。

例如,您可以更改存储库持有者类中的映射以考虑该类:

private Map<Class<?>, Map<String, Repository<?>>> repoMap = new HashMap<>();

即。您可以拥有多个具有相同字符串键的存储库,因为它们由(Class, String)对标识。

或者,您可以输入

interface RepositoryKey<T> {
  // ...
}

当你元素放入持有者时,你会得到一个键入的键:

public <T> RepositoryKey<T> registerRepo(String repoType,Repository<T> repo){
    RepositoryKey<T> key = ...
    repoMap.put(key, repo);
    return key;
}

现在您可以使用密钥来安全地检索它:

Repository<String> repo = new Repository<String>();
RepositoryKey<String> key = holder.registerRepo("mykey", repo);

Repository<String> repo1 = holder.getRepo(key);
repo1.add("fdfd");

请注意, Effective Java 中有一个关于此项的内容:“考虑类型安全的异构容器”。这是第二版中的第29项。你应该阅读更详细的内容。

答案 1 :(得分:1)

而不是

Map<String, Repository<?>> repoMap = new HashMap<String, Repository<?>>();

你应该把回购的类型作为关键

Map<Class<T>, Repository<T>> repoMap = new HashMap<Class<T>, Repository<T>>();

这样你可以保留类型信息并像

一样使用它
Repository<String> repo1 = holder.getRepo(String.class);
            repo1.add("fdfd");