简体   繁体   English

类java的多个泛型类型

[英]Multiple generic type for a class java

is there a way to use a class, with generic types, without setting the maximum number?有没有办法在不设置最大数量的情况下使用具有泛型类型的类? I have this class我有这门课

public class Repository<V> {
    private Map<String, HashSet<V>> repo = new HashMap<>();
    private static Repository instance = null;

    private Repository() {}
    
    public static synchronized Repository getInstance() {
        if(instance == null) {
            instance = new Repository();
        }
        
        return instance;
    }
    
    public void addRepository(String key) throws ClassNotFoundException, IOException {
        repo.put(key, new HashSet<>());
    }

    .....
}

this is a "general repository", the HashMap contains an identifier as a key while as a value have HashSet<V> with the data.这是一个“通用存储库”, HashMap包含一个标识符作为键,而作为值, HashSet<V>包含数据。

I would like each HashSet in the HashMap to contain different class types.我希望HashMap中的每个HashSet都包含不同的类类型。 More precisely, I would like the generic type V to be different for each HashSet within the HashMap更准确地说,我希望泛型类型V对于HashMap中的每个HashSet都不同

how can i fix the code to be able to achieve this result?如何修复代码以实现此结果?

You can't add a class parameter such as Repository<V> and expect V to be different for each type of entry in the map.您不能添加诸如Repository<V>之类的类参数并期望V对于映射中的每种类型的条目都不同。

However, you may do something like this:但是,您可以执行以下操作:

Remove the generic type from Repository:从存储库中删除泛型类型:

public class Repository {
}

Generify the repository map so that it takes a Class<?> as key (instead of a String) and a Set<?> as value):生成存储库映射,以便将Class<?>作为键(而不是字符串)和Set<?>作为值):

private final Map<Class<?>, Set<?>> repo = new HashMap<>();

Then, create one method to add a new repository and a method to get an existing repository as such:然后,创建一个添加新存储库的方法和一个获取现有存储库的方法:

public <T> void addRepository(Class<T> key) {
    Set<?> existing = repo.putIfAbsent(key, new HashSet<>());
    if (existing != null) {
        throw new IllegalArgumentException("Key " + key + " is already associated to a repository");
    }
}

public <T> Set<T> getRepository(Class<T> key) {
    Set<?> subRepo = repo.get(key);
    if (subRepo == null) {
        throw new IllegalArgumentException("No repository found for key " + key);
    }
    return (Set<T>) subRepo; //unchecked cast
}

Note: the getRepository() will perform an unchecked cast, but it is a "safe" unchecked cast since the only way to add a new entry into your map is passing through <T> void addRepository(Class<T> key) and you won't be able to insert values that are not T inside the returned Set<T> .注意: getRepository()将执行未经检查的强制转换,但它是“安全的”未经检查的强制转换,因为将新条目添加到地图中的唯一方法是通过<T> void addRepository(Class<T> key)并且您将无法在返回的Set<T>中插入不是T的值。

Sample usage:示例用法:

Repository repository = Repository.getInstance();
repository.addRepository(String.class);
repository.addRepository(Integer.class);
Set<String> stringRepo = repository.getRepository(String.class);
stringRepo.add("Hey");
stringRepo.add("Jude");
Set<Integer> intRepo = repository.getRepository(Integer.class);
intRepo.add(1);
intRepo.add(4);

However, I think you should have one repository per type, it would be cleaner because with the above solution, you're basically not leveraging at all on Java generics (except for the method <T> used in the getRepository method, for which you need to perform an unchecked cast anyway).但是,我认为每种类型都应该有一个存储库,这会更干净,因为使用上述解决方案,您基本上根本没有利用 Java 泛型(除了getRepository方法中使用的方法<T> ,您无论如何都需要执行未经检查的演员表)。

There's no way to achieve that cleanly.没有办法干净地实现这一目标。 You can create a repository for each type you have, but you can not unite them into one repository with this setup.您可以为您拥有的每种类型创建一个存储库,但您不能使用此设置将它们合并到一个存储库中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM