public class SuperTypeWiIdcards {
static void writeTo(List super Apple> apples) { apples add(new AppleO), apples add(new JonathanO); // apples.add(new FruitO); // Ошибка
}
} /// ~
Аргумент apples является контейнером List для некоторого типа, являющегося базовым для Apple; из этого следует, что Apple и производные от Apple типы могут безопасно включаться в контейнер. Но, поскольку
Ограничения супертипов расширяют возможности по передаче аргументов методу:
//. generics/GenericWriting.java
import java.util.*;
public class GenericWriting {
static
}
static List
static List
static void flO {
writeExact(apples, new AppleO);
// writeExact(fruit, new AppleO); // Ошибка:
// Несовместимые типы: обнаружен Fruit, требуется Apple
}
static
writeWithWildcard(List super T> list, T item) { list.add(item);
}
static void f20 {
writeWithWildcard(apples, new AppleO); writeWithWildcard(fruit, new AppleO);
}
public static void main(String[] args) { flO, f2(); }
} ///.-
Метод writeExact() использует параметр типа «как есть», без метасимволов. На примере fl() мы видим, что этот способ отлично работает — при условии, что в List
В writeWithWildcard() используется аргумент List super Т>, поэтому List содержит конкретный тип, производный от Т; следовательно, Т или производные от него типы могут безопасно передаваться в аргументе методов List. Пример встречается в f2: как и прежде, Apple можно поместить в List
Неограниченные метасимволы
Казалось бы, неограниченный метасимвол <@062> должен означать «все, что угодно», а его использование эквивалентно использованию низкоуровневого типа. В самом деле, на первый взгляд компилятор подтверждает эту оценку:
//: generics/UnboundedWi1dcardsl.java
import java.util.*;
public class UnboundedWildcardsl {
static List listl;
static List > list2;
static List extends Object> list3;
static void assignldist list) { listl = list; 1i st2 = list;
// list3 = list; // Предупреждение: непроверенное преобразование // Обнаружен List, требуется List extends Object>
}
static void assign2(List > list) { listl = list; list2 = list; list3 = list;
}
static void assign3(List extends Object> list) { listl = list; list2 = list; list3 = list;
}
public static void main(String[] args) { assignl(new ArrayListO): assign2(new ArrayList()); // assign3(new ArrayListO); // Предупреждение-// Непроверенное преобразование. Обнаружен- ArrayList // Требуется: List extends Object> assignl(new ArrayLi st
}
} ///:-
Во многих ситуациях, подобных рассмотренной, для компилятора совершенно не существенно, используется низкоуровневый тип или >. Конструкцию > можно считать обычным украшением; впрочем, она обладает некоторой практической ценностью, потому что фактически означает: «Код написан с учетом параметризации Java, и здесь эта конструкция означает не то, что я использую низкоуровневый тип, а то, что параметр параметризации может содержать произвольный тип».
Второй пример демонстрирует важное практическое использование неограниченных метасимволов. Когда вы имеете дело с несколькими параметрами, иногда важно указать, что один параметр может относиться к произвольному типу, а другой ограничить определенным типом:
//: generics/UnboundedWi1dcards2.java
import java.util.*;