2016-02-10 7 views
4

Я начал работать с Java недавно и все еще запутался при работе с родовыми типами. Ниже приведен упрощенный сценарий, когда у меня возникают некоторые проблемы.Разрешение родового типа Java

У меня есть класс, которым владеет картой, используя тип класса как ключ и коллекцию объектов этого класса:

public class GenericListInside { 
    private Map<Class<?>, List<?>> mapping = new HashMap<>(); 

    public <T> void addListing(Class<T> clazz, List<T> object) { 
     mapping.put(clazz, object); 
    } 
} 

Я могу назвать addListing без проблем:

GenericListInside gli = new GenericListInside(); 
List<Foo> list = new ArrayList<>(); 
//add something to list 
gli.addListing(Foo.class, list); 

Теперь я решил создать класс для обеспечения жидкостного интерфейса. Что-то вроде:

with(Foo.class).use(list); 

Тогда я пришел с:

public class FluidInserter<T> { 
    Class<T> clazz; 
    GenericListInside gli = new GenericListInside(); 

    public FluidInserter with (Class<T> clazz) { 
     this.clazz = clazz; 
     return this; 
    } 

    public <T> void use(List<T> list) { 
     gli.addListing(clazz, list); 
    } 
} 

Но когда я пытаюсь скомпилировать я получаю:

Error:(18, 12) java: method addListing in class util.GenericListInside cannot be applied to given types;
required: java.lang.Class,java.util.List
found: java.lang.Class,java.util.List
reason: inferred type does not conform to equality constraint(s)
inferred: T
equality constraints(s): T,T

Это сообщение немного сбивает с толку ... может кто-нибудь выяснить, что я делаю неправильно?

ответ

4

Общий метод вашего жидкостного строителя принимает параметр общего метода, но этот параметр не совпадает с типом вашего поля clazz, несмотря на совпадение имени.

Просто удалите <T> из вашего объявления методы, оставляя List<T> в качестве параметра:

public void use(List<T> list) { 
    gli.addListing(clazz, list); 
} 

Off темы примечание: вы не хотите, чтобы вернуть сырую напечатанное FluidInserter в методе with. Измените тип возвращаемого значения:

public FluidInserter<T> with (Class<T> clazz) 
+0

Вы правы. Спасибо за ответ и вне темы. – marcellorvalle

+0

@marcellorvalle, пожалуйста! – Mena

3

Проблема с определением вашего метода use(List<T> list):

public <T> void use(List<T> list) { 
    gli.addListing(clazz, list); 
} 

Здесь вы скрывается класс-Scoped типа параметра T, вводя параметр типа с одним и тем же именем.

Это должно быть достаточно:

public void use(List<T> list) { 
    gli.addListing(clazz, list); 
} 

и он должен собрать очень хорошо, так как T уже определена на уровне класса.

+0

Да! вы и Мена правы. Спасибо! – marcellorvalle

+0

Добро пожаловать. –

2

Вы проблема заключается в следующем объявлении:

public <T> void use(List<T> list) { 
    gli.addListing(clazz, list); 
} 

Как вы уже определили общий <T> на уровне класса, нет необходимости generify метод.

Я предлагаю вам изменить подпись к следующему:

public void use(List<? extends T> list) { 
    // same logic here 
} 

Кроме того, в качестве примечания, я думаю, вы должны также сделать GenericListInside родовым.В настоящее время определение поля mapping позволяет смешивать типы в ключе и значение, которое вы не хотите.

Редактировать

Вы можете добавить родовое к GenericListInside, как это:

public class GenericListInside<T> { 

    private final Map<Class<T>, List<T> mapping = new HashMap<>(); 

    public void addListing(Class<T> clazz, List<T> list) { 
     mapping.put(clazz, list); 
    } 
} 
+0

Спасибо, Данаил! О вашем последнем комментарии: меня действительно беспокоили типы внутри поля отображения и надеюсь, что метод addListing может гарантировать сплоченность. Я не мог понять, как я могу решить эту проблему, создав класс. Не могли бы вы подробнее рассказать об этом? – marcellorvalle

+0

@marcellorvalle Проверьте обновление, которое я сделал для своего ответа. –

+0

На первый взгляд мысль, что это ограничит мою карту одним типом класса. Когда я протестировал это, я увидел, что это неправда. Мне нужно глубже взглянуть на дженерики ... Спасибо! – marcellorvalle