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.
I would like each HashSet
in the HashMap
to contain different class types. More precisely, I would like the generic type V
to be different for each HashSet
within the HashMap
how can i fix the code to be able to achieve this result?
CodePudding user response:
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.
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):
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>
.
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).
CodePudding user response:
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.