В продолжение этого. Написал пример, чтобы понять разницу между обобщенными типами (generics, <T>) и подстановочными выражениями (wildcards, <?>)
Вопрос №1: почему List<Child> pl6 = makeList1(new Grandson()); ругается на несовместимые типы? Ведь в сигнатуре makeList1 уже прописан Child. Или такая конструкция хотя и задает ограничения на тип, но позволяет пихать в параметризированный контейнер только одинаковые типы List<Child> - только Child, в List<Grandson> только Grandson, но не позволяет создавать List<Parent>?
Вопрос №2: конструкция List<Child> pl2 = makeList(new Grandson(), new Child()); работает, хотя, насколько я знаю, не должна. может дело в сигнануре makeList()?
Вопрос №3: какие ереси и идеологически неверные косяки я допустил в примере?
Собственно сам пример:
import java.util.*;
class Parent{}
class Child extends Parent{}
class Grandson extends Child{}
class GenericsVsWildcards{
static <T> List<T> makeList(T ... args){
List<T> result = new ArrayList<T>(Arrays.<T>asList(args));
return result;
}
static <T extends Child> List<T> makeList1(T arg){
List<T> result = new ArrayList<T>();
result.add(arg);
return result;
}
public static void main(String[] args){
/********* Wildcard tests ********/
//Только указанный тип и наследники
List<? extends Child> pl = new ArrayList<Child>(Arrays.<Child>asList(
//new Parent(), //Низзя
new Child(),
new Grandson()
));
//Получается, допустимы указанный тип и наследники
List<? super Child> pl1 = new ArrayList<Child>(Arrays.<Child>asList(
//new Parent() //Тоже низзя, Эккель был прав
new Child(),
new Grandson()
));
/********* Ceneric tests ********/
//Так работает, хотя, в теории, не должно. Может быть из-за объявления Т не массивом?
List<Child> pl2 = makeList(new Grandson(), new Child());
//A так - нет
//List<Child> pl3 = makeList(new Grandson());
//List<Child> pl4 = makeList( new Child(), new Grandson(), new Parent());
List<Child> pl5 = makeList1(new Child()); //Работает, как и ожидалось
//List<Child> pl6 = makeList1(new Grandson()); //А так нет, хотя ожидалось
}
}