У меня произошла ошибка компиляции дженериков, когда я создал карту с типами ключевых значений, которые используют дженерики, и затем я пытаюсь вставить эту карту.
Позвольте мне выложить код, прежде чем я задам вопрос , Я максимально упростил код для этого вопроса.
Вот весь код, который компилируется.
public interface Cache {
}
public class ExampleCache implements Cache {
}
public interface Item {
}
public class ExampleItem implements Item {
}
public interface Loader<C extends Cache> {
void load(C cache);
}
public class ExampleLoader<C extends Cache> implements Loader<ExampleCache> {
@Override
public void load(ExampleCache cache) {
}
}
А вот класс, который не компилируется.
import java.util.HashMap;
import java.util.Map;
public class Registry {
private final Map<String, Cache> caches = new HashMap<>();
private final Map<String, Loader<Cache>> loaders = new HashMap<>();
public Registry() {
caches.put("cache1", new ExampleCache());
Loader<ExampleCache> exampleLoader = new ExampleLoader<>();
// PROBLEM LINE: this line does not compile
// there is a red underline under 'exampleLoader'
loaders.put("cache1", exampleLoader);
}
public void loadAll() {
for (Map.Entry<String, Loader<Cache>> entry : loaders.entrySet()) {
String cacheName = entry.getKey();
Loader<Cache> loader = entry.getValue();
Cache cache = caches.get(cacheName);
loader.load(cache);
}
}
}
Ошибка, которую я получаю, приведена ниже.
Error:(19, 31) java: incompatible types: Loader<ExampleCache> cannot be converted to Loader<Cache>
Что я делаю не так? Пожалуйста, объясните свои рассуждения, чтобы я мог глубже понять, что я делаю неправильно. Кроме того, при предложении решения, пожалуйста, убедитесь, что весь код выше компилируется. У меня были случаи, когда, если я исправляю одну область, тогда другая ломается.
Спасибо.
Edit1 : Кто-то предложил изменить объявление карты загрузчика на:
private final Map<String, Loader<? extends Cache>> loaders = new HashMap<>();
Но это нарушает метод loadAll () под ним.
import java.util.HashMap;
import java.util.Map;
public class Registry {
private final Map<String, Cache> caches = new HashMap<>();
private final Map<String, Loader<? extends Cache>> loaders = new HashMap<>();
public Registry() {
caches.put("cache1", new ExampleCache());
Loader<ExampleCache> exampleLoader = new ExampleLoader<>();
loaders.put("cache1", exampleLoader);
}
public void loadAll() {
for (Map.Entry<String, Loader<? extends Cache>> entry : loaders.entrySet()) {
String cacheName = entry.getKey();
Loader<? extends Cache> loader = entry.getValue();
Cache cache = caches.get(cacheName);
// NEW PROBLEM LINE: this line does not compile
loader.load(cache);
}
}
}
Новая ошибка компиляции:
Error:(26, 25) java: incompatible types: Cache cannot be converted to capture#1 of ? extends Cache
Редактировать 2 : Похоже, решение Энди Тернера сработало! Хотя он скрывает нагрузку внутри нового класса, похоже, что это самый удачный компромисс из всех, что я могу иметь.
import java.util.HashMap;
import java.util.Map;
public class Registry {
static class CacheLoader<C extends Cache> {
final C cache;
final Loader<C> loader;
CacheLoader(C cache, Loader<C> loader) {
this.cache = cache;
this.loader = loader;
}
public void load() {
loader.load(cache);
}
}
private final Map<String, CacheLoader<?>> cacheLoaders = new HashMap<>();
public Registry() {
cacheLoaders.put("cache1", new CacheLoader<>(new ExampleCache(), new ExampleLoader<>()));
}
public void loadAll() {
for (CacheLoader<?> cacheLoader : cacheLoaders.values()) {
cacheLoader.load();
}
}
}