Список

У меня есть вопрос о дженериках по Java. Я объявил общий список:

List<? extends MyType> listOfMyType;

Затем каким-то способом я пытаюсь создать экземпляр и добавить элементы в этот список:

listOfMyType = new ArrayList<MyType>();
listOfMyType.add(myTypeInstance); 

Где myTypeInstance - это просто объект типа MyType; он не компилируется. Он говорит:

Метод add (захват # 3-из? Расширяет MyType) в типе List ‹захват # 3-из? extends MyType> не применяется для аргументов (MyType)

Любая идея?


person Lancelot    schedule 27.05.2009    source источник
comment
Если класс Bar расширяет класс Foo, а класс Baz имеет generic ‹T›, тогда Baz ‹Foo› waldo = new Baz ‹Bar› () не будет работать, потому что Baz ‹Bar› не является подклассом Baz ‹Foo›, Bar является подклассом из Foo. Подклассификация не применяется к дженерикам. ArrayList ‹Object› flob = new ArrayList ‹Double› () работать не будет. Проще говоря, наследование не распространяется на дженерики. Поскольку вы занимаетесь List ‹? расширяет MyType ›у вас может быть список‹ Некоторые подтипы ›= new ArrayList ‹MyType›. Поскольку они не такие. нет буэно.   -  person JustAFellowCoder    schedule 09.04.2019


Ответы (5)


Вы не можете делать "пут" с расширениями. Посмотрите Generics - Get and Put rule.

person Surya    schedule 27.05.2009
comment
Как говорит Джош Блох: Помните PECS: Producer Extends, Consumer Super. Поскольку listOfMyType является потребителем (вы добавляете к нему), super действителен, а extends - нет. - person Michael Myers; 28.05.2009
comment
Суть педантизма: вы можете put null с расширениями. Также вы можете зафиксировать тип и поместить ссылки, которые у вас были ранее. - person Tom Hawtin - tackline; 17.04.2013

Учитывать:

class MySubType extends MyType {
}

List<MySubType> subtypeList = new ArrayList<MySubType>();
List<? extends MyType> list = subtypeList;
list.add(new MyType());
MySubType sub = subtypeList.get(0);

sub теперь содержит MyType, что очень неправильно.

person Tom Hawtin - tackline    schedule 27.05.2009

Вам не нужно использовать синтаксис захвата подстановочных знаков в вашем случае, просто объявляя

List<MyType> listOfMytype;

должно хватить. Если вы хотите точно знать, почему, Java Generics Tutorial есть больше, чем вы когда-либо хотели бы знать об эзотерическом безумии Java Generics. На странице 20 рассматривается ваш конкретный случай.

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

person Cameron Pope    schedule 27.05.2009

Здесь есть похожая тема: Как можно добавлять элементы в универсальную коллекцию с подстановочными знаками?

Чтобы понять, как работают дженерики, просмотрите этот пример:

    List<SubFoo> sfoo = new ArrayList<SubFoo>();
    List<Foo> foo;
    List<? extends Foo> tmp;

    tmp = sfoo;
    foo = (List<Foo>) tmp;

Дело в том, что это было разработано не для локальных переменных / переменных-членов, а для сигнатур функций, поэтому это так задорно.

person zslevi    schedule 23.03.2011

Я не знаю, действительно ли это поможет вам, но это то, что мне пришлось использовать при вызове универсального метода Spring Framework и желании вернуть также общий список:

public <T> List<T> findAll(String tableName,Class<?> table) {
    String sql = "SELECT * FROM "+ tableName ;
    List<?> entities = getSimpleJdbcTemplate().query(sql,
            ParameterizedBeanPropertyRowMapper.newInstance(table));
            return (List<T>) entities;
}

Кажется, для параметризации нужно использовать? войдите в список, чтобы получить результаты, а затем приведите список к ожидаемому возвращаемому типу.

Меня все еще ослепляют дженерики ...

person will824    schedule 16.03.2012
comment
не создавайте SQL-запросы путем конкатенации строк - см. SQL-инъекцию - person TajnosAgentos; 13.09.2018