Тип вывода с использованием типа возврата, wild card и типа пересечения
Я пытаюсь объявить интерфейс, содержащий метод, который вернет список вещей, которые реализуют как Comparator<Object>
, так и Action
, i.e.
<T extends Comparator<Object> & Action> List<T> getThings();
Это компилируется отлично, но проблема возникает, когда я пытаюсь вызвать этот метод. Я хочу иметь возможность сделать это:
List<Action> things = getThings();
List<Comparator<Object>> things = getThings();
Когда я пытаюсь сделать это, я получаю следующую ошибку компиляции:
incompatible types; no instance(s) of type variable(s) T exist so that
java.util.List<T> conforms to java.util.List<javax.swing.Action>
found : <T>java.util.List<T>
required: java.util.List<javax.swing.Action>
Не работает и следующее:
List<? extends Action> things = getThings();
List<? extends Comparator<Object>> things = getThings();
Другим способом достижения этого эффекта является создание пустого интерфейса, который расширяет как Comparator<Object>
, так и Action
и использует это как возвращаемый тип, т.е.
public interface ComparatorAction extends Comparator<Object>, Action { }
List<ComparatorAction> getThings();
Но я не хочу этого делать. Должен быть способ сделать то, что я хочу, правильно? Любые идеи?
Спасибо!
P.S. У меня тяжелое время подходит для хорошего заголовка для этого сообщения, поэтому не стесняйтесь его менять.
Ответы
Ответ 1
Вы также можете параметризовать метод (ы), из которого вы вызываете getThings()
. Например:
public static <U extends Comparator<Object> & Action> void main(String[] args) {
List<U> l = getThings();
Action a = l.get(0);
Comparator<Object> c = l.get(0);
}
Ответ 2
List<? extends Action> things = getThings();
List<? extends Comparator<Object>> things = getThings();
edit Это была моя первая реакция. Тогда я подумал об этом, и я не думал, что вывод может работать, поэтому я удалил ответ.
Проверка спецификации снова, они должны работать. Он компилируется в JDK7, но сбой в JDK6. Я думаю, там ошибка, которую они исправили.
изменить 2 нет... Я снова прочитал спецификацию (JLS3 # 15.12.2.8), и теперь я не думаю, что вывод должен работать. JDK6 был прав в отказе от вывода. (Я сомневаюсь, что JDK7 представил новую ошибку, возможно, что правила вывода обновляются, поэтому JDK7 корректен в соответствии с новыми правилами. Я не уверен)
В соответствии с JLS3, сначала есть подстановочный знак, вводится новый параметр типа W
, который имеет верхнюю границу Action
. Тогда вывод имеет следующие начальные ограничения:
List<W> >> List<T>
Comparable >> T
Action >> T
Первое ограничение ограничивает ограничение на равенство T=W
и что он делает вывод.
Теперь компилятор проверяет, удовлетворяет ли предполагаемая T
ее границам, то есть,
W :< Comparable
W :< Action
Ответ отрицательный, 1-я оценка не может быть выполнена. (IntelliJ показывает хорошее сообщение об ошибке (лучше, чем javac's): "Inferred type": extends Action (т.е. W) для параметра типа "T" не находится в пределах его границы, должен реализовывать Comparable ")
edit 3 вопрос заключается в том, должен ли быть захват подстановочных знаков до вывода. это мне непонятно. Если не должно быть, то имеем
List<? extends Action> >> List<T>
Comparable >> T
Action >> T
что дает
T :< Action
T :< Comparable
поэтому T=Comparable & Action
Ответ 3
Когда вы возвращаете такой List<T>
, T
относится к некоторому (неизвестному) типу, который является подтипом Action
и Comparator<Object>
и является (предпочтительно самым низким) общим супертипом все элементы в списке. Если такого типа не существует, вы, вероятно, столкнетесь с проблемами.
Если вам все равно, что T
, вы можете использовать переменную типа, как предлагает Дейв Коста, или вы можете использовать подстановочный знак
List<? extends Action> l = getThings();
List<? extends Comparator<Object>> l2 = getThings();