ключевое слово java generics super
я прошел через эти темы
тем не менее, я все еще кажусь немного потерянным с super ключевые слова:
когда мы объявляем сбор так:
List<? super Number> list = null;
list.add(new Integer(0));//this compiles
list.add(new Object());//this doesn't compile
не должно ли быть наоборот - у нас есть список, который содержит некоторые объекты (неизвестного типа), которые родители
Number. Так чтоObjectдолжно соответствовать (так как это родительNumber), иIntegerне стоит. В противном случае по некоторым причинам.
если у нас есть следующий код
static void test(List<? super Number> param) {
param.add(new Integer(2));
}
public static void main(String[] args) {
ArrayList<String> sList = new ArrayList<String>();
test(sList); //will never compile, however...
}
невозможно скомпилировать приведенный выше код (и мое здравомыслие предполагает, что это правильное поведение), но основная логика может доказать обратное:
String is Object, Object is superclass of Number. So String should work.
Я знаю, что это безумие, но разве это не причина, почему они этого не сделали разрешить
<S super T>конструкции? Если да, то почему<? super T>разрешено?
может ли кто-нибудь помочь мне восстановить недостающую часть этой логической цепочки?
6 ответов:
ограниченный подстановочный знак в
List<? super Number>может захватитьNumberи любой из его супертипов. Так какNumber extends Object implements Serializable, это означает, что единственные типы, которые в настоящее время захватывают-конвертируемые поList<? super Number>являются:
List<Number>List<Object>List<Serializable>обратите внимание, что вы можете
add(Integer.valueOf(0))для любого из вышеперечисленных типов. однако, вы НЕ МОГУadd(new Object())доList<Number>илиList<Serializable>, так как это нарушает безопасность общего типа правило.отсюда не правда, что вы можете
addлюбой супертипNumberдоList<? super Number>; Это просто не так, как ограниченные подстановочные знаки и преобразования захвата работы. Вы не объявляетеList<? super Number>потому что вы можете добавитьObjectк нему (вы не можете!); вы делаете, потому что вы хотите добавитьNumberобъекты к нему (т. е. это "потребитель"Number), и просто aList<Number>носит слишком ограничительный характер.ссылки
- Анжелика Лангер дженерики Часто задаваемые вопросы
- что такое ограниченный подстановочный знак?
- когда я буду использовать подстановочный параметризованный тип с нижней границей? ("когда конкретный параметризованный тип будет слишком ограничительным.")
- почему нет нижней границы для параметров типа? ("потому что это не имеет смысла.")
- захват JLS 5.1.10 Преобразования
см. также
- эффективная Java 2-е издание, пункт 28: используйте ограниченные подстановочные знаки для повышения гибкости API
- "PECS означает производитель -
extendsиsuperвопросы
- слишком много, чтобы перечислить, УИК,
new Integer(0)vsvalueOf, etc
первая часть
List<Number>подходитList<? super Number>но вы не можете добавитьObjectдоList<Number>. Вот почему вы не можете добавитьObjectдоList<? super Number>.с другой стороны, вы можете добавить каждый подкласс
Number(Numberвключено) в ваш список.для второй части,
StringэтоObject, аStringэто не суперклассNumber.если бы это работало так, как каждый класс является подклассом
Object,superне было бы никакой значение.
давайте посмотрим все возможные случаи с
List<? super Number>:
- переданный список
List<Object>
List<Object>совместимостьObjectподходит<? super Number>- вы можете добавить любой подтип
NumberдоList<Object>- даже если вы могли бы добавить
Stringв нем единственное, в чем вы уверены, это то, что вы можете добавить любой подклассNumber.
- переданный список
List<Number>:
List<Number>совместимостьNumberподходит<? super Number>- вы можете добавить любой подтип
NumberдоList<Number>
- переданный список
List<Integer>(или любой подклассNumber):
List<Integer>не работа- Integer-это подкласс
Numberтак это именно то, чего мы хотим избежать- даже если
IntegerподходитNumberвы не смогли бы добавить какой-либо подклассNumberнаList<Integer>(например aFloat)superне означает подкласс.
- переданный список
List<String>(или любой класс не расширяетсяNumberни в "супер иерархия"Number(т. е.NumberиObject) :
List<String>не работаетStringне подходитNumber"супер иерархии"- даже если
StringподходитObject(который является суперклассомNumber) вы не были бы уверены, что сможете добавитьNumberдоListкоторые содержат любой подкласс из одного из суперклассовNumber)superне означает какой-либо подкласс одного из суперклассов, это означает только один из суперкласс.
как это работает ?
можно сказать, что до тех пор, как вы можете добавить любой подкласс
NumberС введенныеList, он уважаетsuperключевое слово.
У меня была та же проблема. Я думаю, что синтаксис является причиной путаницы.
List<? super Number>- видимому "список вещей, которые являются супертипами номером", но на самом деле это означает " список вещей, которые имеют номер в качестве своего супертипа".Как только я начал читать его так, он щелкнул.
List<? super Number>означает, что ссылочный тип переменной предполагает, что у нас есть список чисел, объектов или Сериализуемых объектов.причина, по которой вы не можете добавить объект, заключается в том, что компилятор не знает, какие из этих классов находятся в общем определении фактического экземпляра объекта, поэтому он позволяет передавать только число или подтипы числа, такие как Double, Integer и т. д.
допустим у нас есть метод, который возвращает
List<? super Number>. Создание объекта внутри метода заключена с нашей точки зрения, мы просто не можем сказать, если это что-то вроде этого:
List<? super Number> returnValue = new LinkedList<Object>();или
List<? super Number> returnValue = new ArrayList<Number>();таким образом, общий тип может быть объектом или числом. В обоих случаях нам будет разрешено добавить число, но только в одном случае нам будет разрешено добавить объект.
вы должны различать ссылочный тип и фактический тип объекта в этой ситуации.
List<? super Number>такоеList<AncestorOfNumber>где мы можем неявно бросить каждыйNumberк своему супер типуAncestorOfNumber.рассмотрим это: какой общий тип должен быть
????в следующем примере?InputStream mystream = ...; void addTo(List<????> lsb) { lsb.add(new BufferedInputStream(mystream)); } List<BufferedInputStream> lb = new ArrayList<>(); List<InputStream> li = new ArrayList<>(); List<Object> lo = new ArrayList<>(); ... { addTo(lb); addTo(li); addTo(lo); }ответ:
????это все, что мы можем броситьBufferedInputStream, который является тем самым или одним из его предков:? super BufferedInputStream
я не получил его на некоторое время. Многие из ответов здесь, а также другие вопросы показывают, когда и где некоторые обычаи являются ошибками, но не так много, почему.
вот как я, наконец, получил его. Если у меня есть функция, которая добавляет
NumberСList, я мог бы добавить их типаMySuperEfficientNumberкоторый является моим собственным пользовательским классом, который реализуетNumber(но не является подклассомInteger). Теперь абонент может ничего не знать оMySuperEfficientNumber, но пока они знают, чтобы лечить элементы, добавленные в список как ничего более конкретного, чемNumberони будут в порядке.если я объявил свой метод как:
public static void addNumbersToList(List<? extends Number> numbers)тогда вызывающий может пройти в
List<Integer>. Если мой метод добавил aMySuperEfficientNumberдо концаnumbers, то вызывающий абонент больше не будет иметьListнаIntegers и следующий код не будет работать:List<Integer> numbers = new ArrayList<Integer>(); addNumbersToList(numbers); // The following would return a MySuperEfficientNumber not an Integer Integer i = numbers.get(numbers.size()-1)очевидно, что это не может работать. И ошибка будет внутри
addNumbersToListметод. Вы бы что-то получили например:The method add... is not applicable for the arguments (MySuperEfficientNumber), потому что
numbersможет быть любой конкретный видNumber, не обязательно что-то чтоMySuperEfficientNumberсовместим со. Если я перевернул объявление вокруг, чтобы использоватьsuper, метод будет компилироваться без ошибок, но код вызывающего абонента не будет работать с:The method addNumbersToList(List<? super Number>)... is not applicable for the arguments (List<Integer>)потому что мой метод говорит: "Не думайте, что ваш
Listможет быть что-то более конкретное, чемNumber. Я мог бы добавить все виды странноNumbers в список, вам просто нужно справиться с этим. Если вы хотите думать о них как о чем-то еще более общем, чемNumber-- какObject-- это нормально, я гарантирую, что они будут не менееNumbers, но вы можете относиться к ним более широко, если хотите.", тогда как
extendsговорит: "мне действительно все равно, какойListвы даете мне, пока каждый элемент не менееNumber. Это может быть любой видNumber, даже ваш собственный странный, пользовательский, придуманныйNumbers. пока они реализуют этот интерфейс, мы хороший. Я не собираюсь ничего добавлять в ваш список, так как я не знаю, какой конкретный тип вы там используете."
Comments