Przepraszam, ale nie możesz.
Deklaracja wieloznaczna List<? extends Number> foo3oznacza, że zmienna foo3może zawierać dowolną wartość z rodziny typów (zamiast dowolnej wartości określonego typu). Oznacza to, że którekolwiek z tych zadań są prawnymi:
List<? extends Number> foo3 = new ArrayList<Number>; // Number "extends" Number
List<? extends Number> foo3 = new ArrayList<Integer>; // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>; // Double extends Number
Biorąc pod uwagę to, jaki typ obiektu możesz dodać do List foo3tego, byłby legalny po którymkolwiek z powyższych możliwych ArrayListprzypisań:
- Nie możesz dodać,
Integerponieważ foo3może wskazywać na List<Double>.
- Nie możesz dodać,
Doubleponieważ foo3może wskazywać na List<Integer>.
- Nie możesz dodać,
Numberponieważ foo3może wskazywać na List<Integer>.
Nie możesz dodać żadnego obiektu, List<? extends T>ponieważ nie możesz zagwarantować, na jaki rodzaj obiektu Listwskazuje, więc nie możesz zagwarantować, że obiekt jest w tym dozwolony List. Jedyną „gwarancją” jest to, że możesz tylko z niego czytać, a otrzymasz Tpodklasę lub T.
Logika odwrotna dotyczy supernp List<? super T>. Są to legalne:
List<? super Number> foo3 = new ArrayList<Number>; // Number is a "super" of Number
List<? super Number> foo3 = new ArrayList<Object>; // Object is a "super" of Number
Nie możesz odczytać konkretnego typu T (np. Number), List<? super T>Ponieważ nie możesz zagwarantować, na jaki typ Listnaprawdę wskazuje. Jedyną „gwarancją”, jaką masz, jest możliwość dodania wartości typu T(lub dowolnej podklasy T) bez naruszenia integralności wskazywanej listy.
Doskonałym tego przykładem jest podpis Collections.copy():
public static <T> void copy(List<? super T> dest,List<? extends T> src)
Zwróć uwagę, w jaki sposób srcdeklaracja listy extendspozwala mi przekazać dowolną Listę z rodziny pokrewnych typów List i nadal gwarantuje, że wygeneruje wartości typu T lub podklasy T. Ale nie możesz dodawać do srclisty.
Do destzastosowania deklaracji lista superpozwoli mi przekazać żadnej liście z rodziny pokrewnych typów listy i nadal gwarantować mogę napisać wartość określonego typu T do tej listy. Ale nie można zagwarantować, że odczytam wartości określonego typu T, jeśli przeczytam z listy.
Więc teraz, dzięki uniwersalnym symbolom generycznym, mogę wykonać dowolne z tych wywołań za pomocą tej jednej metody:
// copy(dest, src)
Collections.copy(new ArrayList<Number>(), new ArrayList<Number());
Collections.copy(new ArrayList<Number>(), new ArrayList<Integer());
Collections.copy(new ArrayList<Object>(), new ArrayList<Number>());
Collections.copy(new ArrayList<Object>(), new ArrayList<Double());
Rozważ ten zagmatwany i bardzo szeroki kod, aby ćwiczyć mózg. Skomentowane wiersze są nielegalne, a powód jest podany po prawej stronie wiersza (należy przewinąć, aby zobaczyć niektóre z nich):
List<Number> listNumber_ListNumber = new ArrayList<Number>();
//List<Number> listNumber_ListInteger = new ArrayList<Integer>(); // error - can assign only exactly <Number>
//List<Number> listNumber_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Number>
List<? extends Number> listExtendsNumber_ListNumber = new ArrayList<Number>();
List<? extends Number> listExtendsNumber_ListInteger = new ArrayList<Integer>();
List<? extends Number> listExtendsNumber_ListDouble = new ArrayList<Double>();
List<? super Number> listSuperNumber_ListNumber = new ArrayList<Number>();
//List<? super Number> listSuperNumber_ListInteger = new ArrayList<Integer>(); // error - Integer is not superclass of Number
//List<? super Number> listSuperNumber_ListDouble = new ArrayList<Double>(); // error - Double is not superclass of Number
//List<Integer> listInteger_ListNumber = new ArrayList<Number>(); // error - can assign only exactly <Integer>
List<Integer> listInteger_ListInteger = new ArrayList<Integer>();
//List<Integer> listInteger_ListDouble = new ArrayList<Double>(); // error - can assign only exactly <Integer>
//List<? extends Integer> listExtendsInteger_ListNumber = new ArrayList<Number>(); // error - Number is not a subclass of Integer
List<? extends Integer> listExtendsInteger_ListInteger = new ArrayList<Integer>();
//List<? extends Integer> listExtendsInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a subclass of Integer
List<? super Integer> listSuperInteger_ListNumber = new ArrayList<Number>();
List<? super Integer> listSuperInteger_ListInteger = new ArrayList<Integer>();
//List<? super Integer> listSuperInteger_ListDouble = new ArrayList<Double>(); // error - Double is not a superclass of Integer
listNumber_ListNumber.add(3); // ok - allowed to add Integer to exactly List<Number>
// These next 3 are compile errors for the same reason:
// You don't know what kind of List<T> is really
// being referenced - it may not be able to hold an Integer.
// You can't add anything (not Object, Number, Integer,
// nor Double) to List<? extends Number>
//listExtendsNumber_ListNumber.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Number>
//listExtendsNumber_ListInteger.add(3); // error - can't add Integer to *possible* List<Double>, even though it is really List<Integer>
//listExtendsNumber_ListDouble.add(3); // error - can't add Integer to *possible* List<Double>, especially since it is really List<Double>
listSuperNumber_ListNumber.add(3); // ok - allowed to add Integer to List<Number> or List<Object>
listInteger_ListInteger.add(3); // ok - allowed to add Integer to exactly List<Integer> (duh)
// This fails for same reason above - you can't
// guarantee what kind of List the var is really
// pointing to
//listExtendsInteger_ListInteger.add(3); // error - can't add Integer to *possible* List<X> that is only allowed to hold X's
listSuperInteger_ListNumber.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
listSuperInteger_ListInteger.add(3); // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
List<? extends Number>nie oznacza to „listy obiektów różnych typów, z których wszystkie się rozszerzająNumber”. Oznacza „listę obiektów jednego typu, które się rozszerzająNumber”.