Ненависти к жабе псто
Sep. 22nd, 2011 10:28 pmА вы знаете, почему разные авторы диаметрально противоположно описывают маски с ограничением super? Например, в разных изданиях Хорстманн описывает разное поведение подстановочных типов с ограничением на супертипы.
For example, Pair<? super Manager> has methods
void setFirst(? super Manager)
? super Manager getFirst()
The compiler doesn’t know the exact type of the setFirst method but can call it with any object of type Manager, Employee, or Object, but not a subtype such as Executive.
Это противоречит его более раннему изданию, где в setFirst можно передавать Manager и Executive, но не их супертипы.
Одновременно у Эккеля аналогичная цитата:
the argument is now a List<? super T>, so the List holds a specific type that is derived from T; thus it is safe to pass a T or anything derived from T as an argument to List methods.
Впрочем, эксперимент подтверждает правоту Эккеля:
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()); //А так нет, хотя ожидалось. Происходит это потому, что в
//makeList1(new Grandson()) получается List<Grandson>, который
//не приводится к List<Child>. Хотя, это можно полечить явно указав
//что хочу List<Child>
}
}
For example, Pair<? super Manager> has methods
void setFirst(? super Manager)
? super Manager getFirst()
The compiler doesn’t know the exact type of the setFirst method but can call it with any object of type Manager, Employee, or Object, but not a subtype such as Executive.
Это противоречит его более раннему изданию, где в setFirst можно передавать Manager и Executive, но не их супертипы.
Одновременно у Эккеля аналогичная цитата:
the argument is now a List<? super T>, so the List holds a specific type that is derived from T; thus it is safe to pass a T or anything derived from T as an argument to List methods.
Впрочем, эксперимент подтверждает правоту Эккеля:
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()); //А так нет, хотя ожидалось. Происходит это потому, что в
//makeList1(new Grandson()) получается List<Grandson>, который
//не приводится к List<Child>. Хотя, это можно полечить явно указав
//что хочу List<Child>
}
}