Почему параметр типа Java не может иметь нижнюю границу?

Я понимаю, что вы не можете привязать параметр типа generics Java к нижней границе (т. Е. Используя ключевое слово super ). Я читал то, что Чейтолог Angelika Langer Generics должен был сказать по этому вопросу . Они говорят, что это в основном сводится к тому, что нижняя граница бесполезна («не имеет никакого смысла»).

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

 public static ArrayList createArrayListFullOfEmptyStrings(int i); 

Но это излишне ограничительно для ваших клиентов. Почему они не могут вызвать ваш метод следующим образом:

 //should compile List l1 = createArrayListFullOfEmptyStrings(5); List l2 = createArrayListFullOfEmptyStrings(5); List l3 = createArrayListFullOfEmptyStrings(5); //shouldn't compile List l4 = createArrayListFullOfEmptyStrings(5); 

В этот момент у меня возникнет соблазн попробовать следующее определение:

 public static  List createArrayListFullOfEmptyStrings(int size) { List list = new ArrayList(size); for(int i = 0; i < size; i++) { list.add(""); } return list; } 

Но он не будет компилироваться; ключевое слово super является незаконным в этом контексте.

Мой пример выше плохого примера (игнорируя то, что я говорю ниже)? Почему здесь нет нижней границы? И если это было бы полезно, какова реальная причина, по которой это запрещено в Java?

PS

Я знаю, что лучшая организация может быть примерно такой:

 public static void populateListWithEmptyStrings(List list, int size); List list = new ArrayList(); populateListWithEmptyStrings(list, 5); 

Можем ли мы с этой целью притворяться, что по требованию нам нужно выполнить обе операции в одном вызове метода?

редактировать

@Tom G (справедливо) спрашивает, какая польза от List будет иметь над List . Во-первых, никто не сказал, что возвращенный список неизменен, так что вот одно преимущество:

 List l2 = createArrayListFullOfEmptyStrings(5); l2.add(new StringBuilder("foo").append("bar")); 

В принципе, его недостаточно полезно.

Я думаю, что ваш пример указывает на единственное преимущество нижней границы, функцию, которую часто Restricted Instantiation :

Суть заключается в том, что все, что «супер» связало бы с вами, – это ограничение, что только супертипы числа могут использоваться как аргументы типа . ….

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

Из-за характера polymorphismа и специализации верхние границы гораздо полезнее нижних границ, как описано в FAQ ( Доступ к нестационарным членам и стирание типов ). Я подозреваю, что сложность, введенная нижними границами, не стоит его ограниченного значения.


OP: Я хочу добавить, я думаю, вы показали, что это полезно, просто недостаточно полезно. Придумайте неопровержимые примеры использования убийц, и я верну JSR. 🙂

спецификация действительно говорит о нижних границах параметров типа, например

4.10.2

переменная типа является прямым супертипом ее нижней границы.

5.1.10

новая переменная типа … нижняя граница которой

Похоже, что переменная типа имеет только (ненулевую) нижнюю границу, если она является синтетической в ​​результате захвата подстановочных знаков. Что делать, если язык допускает нижние границы для всех параметров типа? Вероятно, это не вызывает больших проблем, и исключается только упрощение обобщения (ну …). Обновление говорит о том, что теоретическое исследование параметров нижнего ограниченного типа не проводится полностью.

Обновление: документ, утверждающий нижние границы, в порядке: «Недопустимость типа Java-типа: можем ли мы его исправить» Daniel Smith

RETRACT: следующий аргумент неверен. Пример OP является законным.

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

  List l2 = createArrayListFullOfEmptyStrings(5); 

то мы можем добавить к нему не-String, что неверно

  CharSequence chars = new StringBuilder(); l2.add(chars); 

Ну, List не является, но несколько похож на список CharSequence. Ваша потребность может быть решена с помощью шаблона:

 public static List createArrayListFullOfEmptyStrings(int size) // a list of some specific subtype of CharSequence List l2 = createArrayListFullOfEmptyStrings(5); // legal. can retrieve elements as CharSequence CharSequence chars = l2.get(0); // illegal, won't compile. cannot insert elements as CharSequence l2.add(new StringBuilder()); 

Это больше, чем ответ, это другой вариант (возможно, убийца?). У меня есть помощник ModelDecorator. Я хочу, чтобы у него был следующий открытый API

 class ModelDecorator{ public static  ModelDecorator create(Class clazz); public  T from(SUPER fromInstance); } 

Таким образом, заданные classы A, B расширяют A, его можно использовать следующим образом:

 A a = new A(); B b = ModelDecorator.create(B.class).from(a); 

Но я хочу иметь ограничения на T и SUPER, поэтому я убеждаюсь, что только субclassы могут быть созданы с использованием API. В этот момент я могу сделать:

 C c = new C(); B b = ModelDecorator.create(B.class).from(c); 

Где B НЕ НАЙТИ НА C.

Очевидно, если бы я мог:

  public  T from(SUPER fromInstance); 

Это решило бы мою проблему.

Какое преимущество при вводе списка дает вам в этот момент? Когда вы перебираете возвращаемую коллекцию, вы все равно можете сделать следующее:

 for(String s : returnedList) { CharSequence cs = s; //do something with your CharSequence } 

Хм, хорошо, давайте работать с этим. Вы определяете метод:

public static List createArrayListFullOfEmptyStrings(int size) {

Что это значит? Это означает, что если я вызову ваш метод, я верну список суперclassа String. Возможно, он возвращает список String. Возможно, он возвращает список объектов. Я не знаю.

Круто.

Listl1 = createArrayListFullOfEmptyStrings(5);

По вашему мнению, это должно скомпилировать. Но это не так! Я могу поместить Integer в список Object – l1.add(3) . Но если вы возвращаете список String, то это должно быть незаконным.

List l3 = createArrayListFullOfEmptyStrings(5);

По вашему мнению, это должно скомпилировать. Но это не так! l3.get(1) должен всегда возвращать String … но этот метод мог бы вернуть список объектов, что означает, что l3.get (1) может быть, возможно, целым.

Единственное, что работает, это

List l5 = createArrayListFullOfEmptyStrings(5);

Все, что я знаю, это то, что я могу смело называть l4.put("foo") , и я могу безопасно получить Object o = l4.get(2) .

  • Java: Синтаксис и смысл за «[B @ 1ef9157»? Binary / адрес?
  • Java JTextField с подсказкой ввода
  • Maven родительский pom vs modules pom
  • Точка с запятой в конце выражения «if»
  • java.lang.NoClassDefFoundError: org / hamcrest / SelfDescribing
  • Как переместить большие файлы с помощью RestTemplate?
  • Если вы настроили свойства подключения к базе данных в файле server.xml или context.xml
  • JPA, Как использовать один и тот же class (сущность) для сопоставления разных таблиц?
  • Кастинг LinkedHashMap для сложного объекта
  • Исключительные английские слова с Lucene
  • В чем разница между Double.parseDouble (String) и Double.valueOf (String)?
  • Давайте будем гением компьютера.