ключевое слово java generics super



я прошел через эти темы




тем не менее, я все еще кажусь немного потерянным с super ключевые слова:





  1. когда мы объявляем сбор так:



    List<? super Number> list = null;
    list.add(new Integer(0));//this compiles
    list.add(new Object());//this doesn't compile


    не должно ли быть наоборот - у нас есть список, который содержит некоторые объекты (неизвестного типа), которые родители Number. Так что Object должно соответствовать (так как это родитель Number), и Integer не стоит. В противном случае по некоторым причинам.




  2. если у нас есть следующий код



    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> разрешено?




может ли кто-нибудь помочь мне восстановить недостающую часть этой логической цепочки?

987   6  

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), и просто a List<Number> носит слишком ограничительный характер.

ссылки

см. также

  • эффективная Java 2-е издание, пункт 28: используйте ограниченные подстановочные знаки для повышения гибкости API
    • "PECS означает производитель -extends иsuper

вопросы

  • слишком много, чтобы перечислить, УИК,new Integer(0) vs valueOf, 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> (например a Float)
    • 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>. Если мой метод добавил a MySuperEfficientNumber до конца 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

    Ничего не найдено.