Расширение шаблона объекта Java Generics [дубликат]

Именованные группы захвата могут быстро перейти на JavaScript. Предложение для него уже на этапе 3.

Группе захвата может быть присвоено имя с использованием синтаксиса (? ...) для любого имени идентификатора. Регулярное выражение для даты тогда может быть записано как / (? \ D {4}) - (? \ D {2}) - (? \ D {2}) / u. Каждое имя должно быть уникальным и следовать грамматике имени ECMAScript IdentifierName.

Доступ к именованным группам можно получить из свойств свойства групп результата регулярного выражения. Также создаются нумерованные ссылки на группы, как и для неименованных групп. Например:

  let re = / (& lt; year & gt; \ d {4}) - (& lt; month & gt; \ d {2}) - (& lt; day & gt; \  д {2}) / U;  let result = re.exec ('2015-01-02');  // result.groups.year === '2015';  // result.groups.month === '01';  // result.groups.day === '02';  // result [0] === '2015-01-02';  // result [1] === '2015';  // result [2] === '01';  // result [3] === '02';   

15
задан erickson 28 July 2009 в 17:44
поделиться

5 ответов

Используйте это вместо:

1  public List<? extends Foo> getFoos()
2  {
3    List<Foo> foos = new ArrayList<Foo>(); /* Or List<SubFoo> */
4    foos.add(new SubFoo());
5    return foos;
6  }

Как только вы объявляете foos как List<? extends Foo>, компилятор не знает, что безопасно добавлять SubFoo. Что, если ArrayList<AltFoo> было присвоено foos? Это будет действительное назначение, но добавление SubFoo будет загрязнять коллекцию.

28
ответ дан erickson 17 August 2018 в 12:05
поделиться

Следующие будут работать нормально:

public List<? extends Foo> getFoos() {
    List<Foo> foos = new ArrayList<Foo>();
    foos.add(new SubFoo());
    return foos;
}
1
ответ дан SCdF 17 August 2018 в 12:05
поделиться

Просто подумал, что я бы добавил к этому старому потоку, суммируя свойства параметров List, созданных с помощью типов или подстановочных знаков ....

Когда у метода есть параметр / результат, который является List, использование типа экземпляра или подстановочных знаков определяет

  1. Типы списка, которые могут быть переданы методу в качестве аргумента
  2. Типы списка, которые могут быть заполнены из результата метода
  3. Типы элементов, которые могут быть записаны в список в методе
  4. Типы, которые могут быть заполнены при чтении элементов из списка в методе

Param / Тип возврата: List< Foo>

  1. Типы списка, которые могут быть переданы методу в качестве аргумента: List< Foo>
  2. Типы списка, которые могут быть заполнены из Результат метода: List< Foo> List< ? super Foo> List< ? super SubFoo> List< ? extends Foo> List< ? extends SuperFoo>
  3. Типы элементов, которые могут быть записаны в список в пределах метода: Foo & amp; подтипы
  4. Типы, которые могут быть заполнены при чтении элементов из списка в методе: Foo & amp; супертипы (до Object)

Параметр / Тип возврата: List< ? extends Foo>

  1. Типы списка, которые могут быть переданы методу в качестве аргумента : List< Foo> List< Subfoo> List< SubSubFoo> List< ? extends Foo> List< ? extends SubFoo> List< ? extends SubSubFoo>
  2. Типы списка, которые могут быть заполнены из результата метода: List< ? extends Foo> List< ? extends SuperFoo> List< ? extends SuperSuperFoo>
  3. Типы элементов, которые могут быть записаны для перечисления в методе: Нет! Невозможно добавить.
  4. Типы, которые могут быть заполнены при чтении элементов из списка в методе: Foo & amp; супертипы (до Object)

Параметр / Тип возврата: List<? super Foo>

  1. Типы списка, которые могут быть переданы методу в качестве аргумента : List< Foo> List< Superfoo> List< SuperSuperFoo> List< ? super Foo> List< ? super SuperFoo> List< ? super SuperSuperFoo>
  2. Типы списка, которые могут быть заполнены из результата метода: List< ? super Foo> List< ? super SubFoo> List< ? super SubSubFoo>
  3. Типы элементов, которые могут быть записаны для перечисления в рамках метода: Foo & amp; супертипы
  4. Типы, которые могут быть заполнены при чтении элементов из списка в методе: Foo & amp; супертипы (до Object)

Интерпретация / комментарий

  • потребности внешних вызывающих абонентов приводят дизайн декларации метода, т.е. публичный API (обычно первичное рассмотрение)
  • потребности в логике внутреннего логического устройства приводят любые дополнительные решения к фактическим типам данных, объявленным и построенным внутренне (обычно вторичное рассмотрение)
  • используют List<Foo>, если код вызывающего абонента всегда сфокусирован при манипулировании классом Foo, поскольку он максимизирует гибкость как для чтения, так и для записи
  • , используйте List<? extends UpperMostFoo>, если может быть много разных типов абонентов, ориентированных на управление другим классом (не всегда Foo), и есть один самый верхний класс в иерархии типов Foo, и если этот метод предназначен для внутренней записи в список, а чтение списка вызывающих абонентов читается. Здесь метод может внутренне использовать List< UpperMostFoo> и добавлять к нему элементы, прежде чем возвращать List< ? extends UpperMostFoo>
  • , если может быть много разных типов вызывающих, сфокусированных на управлении другим классом (не всегда Foo), и если чтение и запись в список требуется, и в иерархии типов Foo есть один самый низкий класс, тогда имеет смысл использовать List< ? super LowerMostFoo>
14
ответ дан stites 17 August 2018 в 12:05
поделиться
  • 1
    Я думаю, что 3 и 4 для List<? super Foo> ошибочны. Это должно быть «Foo & amp; Подтипы & Quot; и "Объект" соответственно. – FuegoFro 22 August 2016 в 18:36

Попробуйте:

public List<Foo> getFoos() {
    List<Foo> foos = new ArrayList<Foo>();
    foos.add(new SubFoo());
    return foos;
}

Генерирующий конструктор ArrayList должен иметь определенный тип для параметризации, вы не можете использовать '?' wildcard там. Изменение экземпляра «new ArrayList & lt; Foo & gt; ()» разрешило бы первую ошибку компиляции.

Объявление переменной foos может иметь подстановочные знаки, но поскольку вы знаете точный тип, он делает больше чтобы ссылаться на информацию о том же типе. Что вы теперь говорите, что foos содержит определенный подтип Foo, но мы не знаем, что. Добавление SubFoo может быть запрещено, поскольку SubFoo не является «всеми подтипами Foo», Изменение декларации в «List & lt; Foo & gt; foos =» решает вторую ошибку компиляции.

Наконец, я бы изменил тип возвращаемого значения на «List & lt; Foo & gt;»; поскольку клиенты этого метода не смогут многое сделать с возвращаемым значением, как определено в настоящее время. Вы должны редко использовать подстановочные знаки в типах возврата. При необходимости используйте сигнатуру с параметризованным методом, но предпочитайте ограниченные типы только в аргументах метода, так как который оставляет его до вызывающего абонента, который может передавать конкретные типы и работать и соответственно.

6
ответ дан user 17 August 2018 в 12:05
поделиться
  • 1
    Я не согласен с вашим последним моментом. Тип обратного подстановок очень полезен, если вызывающему абоненту просто нужно получить вещи из списка. – newacct 16 July 2012 в 19:16

Чтобы понять, как работают дженерики, посмотрите этот пример:

    List<SubFoo> sfoo = new ArrayList<SubFoo>();
    List<Foo> foo;
    List<? extends Foo> tmp;

    tmp = sfoo;
    foo = (List<Foo>) tmp;

Дело в том, что это не было предназначено для локальных / членных переменных, а для сигнатур функций, вот почему это так осел в обратном направлении.

1
ответ дан zslevi 17 August 2018 в 12:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: