Несоответствие типов с ограниченным символом подстановки?супер тип - PullRequest
1 голос
/ 07 января 2012

У меня проблема с правильным преобразованием типов.Я предполагаю, что ограниченный универсальный шаблонне работает с реализациями интерфейса.

// sample class definitions
public interface IFace<T> { ... } 
public class MyClass<T1, T2> { ... }
public class UtilityClass<T> {
    public List<MyClass<T, ? super IFace<T>>> getList() { ... }
}
public class Actor extends SomeObj implements IFace<TypeA> { ... }

// use...
UtilityClass<TypeA> utility = new UtilityClass<TypeA>();
List<MyClass<TypeA, Actor>> list = utility.getList();

Type mismatch: cannot convert from List<MyClass<TypeA, ? super IFace<TypeA>> to List<MyClass<TypeA, Actor>>

Ответы [ 3 ]

4 голосов
/ 07 января 2012

Ссылаясь на «Эффективную Java» Джошуа Блоха, 2-е издание:

Не используйте подстановочные типы в качестве типов возврата .Вместо того, чтобы предоставлять дополнительную гибкость вашим пользователям, это заставило бы их использовать подстановочные знаки в клиентском коде.

При правильном использовании подстановочные типы почти невидимы для пользователей класса.Они заставляют методы принимать параметры, которые они должны принять, и отклоняют те, которые они должны отклонять. Если пользователь класса должен думать о подстановочных типах, возможно, что-то не так с API класса .

1 голос
/ 07 января 2012

Когда вы начинаете работать с дженериками, нужно обязательно прочитать это руководство . Если вы прочтете раздел «Общие и подтипы» на стр. 4, вы поймете, почему вы получаете эту ошибку. Это никак не связано с тем, что вы используете интерфейс

0 голосов
/ 07 января 2012

Интуитивно можно попытаться решить проблему, сделав метод общим:

public <X super IFace<T>> List<MyClass<T, X> getList() { ... }

Но этот синтаксис недопустим, так как обычно не имеет смысла давать нижнюю границу для параметров типа, используя super. См. Эту статью для хорошего объяснения почему: http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ107

Edit:

Глядя на ваш код, я думаю, вы, возможно, путаете super с extends в определении границ параметра типа. было бы значимым, если бы getList() возвратил List<MyClass<T, ? extends IFace<T>>> вместо этого, поскольку это указывает верхний , связанный с параметром второго типа MyClass (другими словами, этот тип должен быть чем-то реализующим IFace<T>).

Поскольку ответ natix указывает , использование подстановочных знаков в универсальных типах возвращаемых данных не рекомендуется, поскольку оно эффективно скрывает часть информации универсального типа для возвращаемого объекта. Вместо этого сделайте метод универсальным:

public <X extends IFace<T>> List<MyClass<T, X> getList() { ... }

Что позволяет вызывающему коду указывать тип X через определение типа.

...