Универсальная коллекция Java универсального типа с ограниченным подстановочным знаком

Пожалуйста, помогите мне с этим:

Если Lion IS-A Animal и задано Cage<T>:

Cage<? extends Animal> c = new Cage<Lion>(); // ok,

но

Set<Cage<? extends Animal>> cc = new HashSet<Cage<Lion>>(); // not ok

Чего я здесь не вижу?


person ar_    schedule 20.05.2010    source источник


Ответы (3)


При присвоении переменной (Set<T>) универсального типа T без подстановочных знаков присваиваемый объект должен иметь точно T в качестве своего универсального типа (включая все параметры универсального типа T, подстановочные знаки и не подстановочные знаки). В вашем случае T - это Cage<Lion>, который не совпадает с типом Cage<? extends Animal>.

Что вы можете сделать, поскольку Cage<Lion> можно присвоить Cage<? extends Animal>, это использовать тип подстановочного знака:

Set<? extends Cage<? extends Animal>> a = new Set<Cage<Lion>>();
person ILMTitan    schedule 20.05.2010
comment
Спасибо, для меня это была недостающая часть. - person ar_; 23.05.2010

Это неправильно, потому что если бы это было разрешено, то это было бы законно:

Set<Cage<? extends Animal>> cc = new HashSet<Cage<Lion>>(); 
cc.add(new Cage<Tiger>()); // legal -- Cage<Tiger> is a Cage<? extends Animal>

Cage<Tiger> находится в пределах объявления, но не определения, поэтому это приведет к сбою.

person Michael Myers    schedule 20.05.2010
comment
Как Java может решить, применять контравариантность/ковариантность или нет? - person Simon; 20.05.2010
comment
Насколько я понимаю, Java рассматривает дженерики как инвариантные (но, как ни странно, рассматривает массивы как ковариантные и проверяет типы во время выполнения), но, написав методы с подходящими параметрами подстановочных знаков (extends или super в зависимости от ситуации), а также немного приведения и подавления непроверенных преобразований, вы можете произвести впечатление того, что подходит в вашем случае. - person pdbartlett; 20.05.2010

Тебе нужно:

Set<? extends List<? extends Number>> cc = new HashSet<ArrayList<Integer>>();

Чтобы объяснить, почему... Я думаю, вернемся к более простой версии вашего примера:

Number a = new Integer(1); // OK
Set<Number> b = new HashSet<Integer>(); // not OK

это не работает, потому что это позволит

b.add(new Double(3.0));
person Sean Owen    schedule 20.05.2010