#java #generics #iterator
#java #дженерики #итератор
Вопрос:
Возможно, я что-то упускаю, но я подумал, что если я объявлю свой класс как таковой:
public class Something<T> implements Iterable<Iterable<T>> {
public Something(Iterable<Iterable<T>> input) {
...
Я должен быть в состоянии создать его экземпляр как таковой:
ArrayList<ArrayList<String>> l = new ArrayList<ArrayList<String>>();
Something<String> s = Something<String>(l);
К сожалению, это выдает мне ошибку. Я думал, что ArrayLists являются итерируемыми, поэтому они должны точно соответствовать определению моего конструктора.
Ответ №1:
Вам нужно изменить свой конструктор, чтобы принимать все, что расширяет Iterable<T>
public Something(Iterable<? extends Iterable<T>> list){}
Причина этого в том, что универсальные типы не могут буквально расширять другие универсальные типы. A List<String>
не может быть присвоен a List<CharSequence>
. Ключевое слово extends
допускает этот тип присваивания.
Комментарии:
1. Спасибо, но теперь я получаю предупреждения здесь:
public class Something<T> implements Iterable<Iterable<T>> { private Iterable<Iterable<T>> input; public Something(Iterable<? extends Iterable<T>> input) { this.input = (Iterable<Iterable<T>>)input; }
2. Я предлагаю найти копию Effective Java Джоша Блоха и прочитать «PECS». Это поможет вам действительно понять, что происходит. В любом случае вам нужно иметь
Iterable<? extends Iterable<T>
везде, где вы собираетесь назначитьArrayList<ArrayList<String>>
3. или, возможно, даже
Iterable<? extends Iterable<? extends T>>
Ответ №2:
Подтипирование с помощью generics очень неинтуитивно. Для того, что вы хотите сделать, вам нужны подстановочные знаки, и это было бы довольно некрасиво.
В разделе 3 есть отличное объяснение — http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf