Почему не работает полиморфизм с дженериками?

164
31 мая 2021, 19:20

для

Comparable<BigDecimal> c = new BigDecimal("");

все отлично, но для

List<Comparable<BigDecimal>> l = new ArrayList<BigDecimal>();

начинает ругаться на не соответсвтие типов

Answer 1

«Дженерики» инвариантны.

Приведем пример:

List<Integer> ints = Arrays.asList(1,2,3);
List<Number> nums = ints; // compile-time error. Проблема обнаружилась на этапе компиляции
nums.set(2, 3.14);
assert ints.toString().equals("[1, 2, 3.14]");

Если взять список целых чисел, то он не будет являться ни подтипом типа Number, ни каким-либо другим подтипом. Он является только подтипом самого себя.

То есть List <Integer> — это List<Integer> и ничего больше.

Компилятор позаботится о том, чтобы переменная ints, объявленная как список объектов класса Integer, содержала только объекты класса Integer и ничего кроме них. На этапе компиляции производится проверка, и у нас в рантайме уже ничего не упадет.

Казалось бы, удобно было бы использовать подход приведенный выше, но дженерики сделаны так, чтобы, если код компилируется, то в рантайме — не должно быть исключительных ситуаций.

Компилятор не даст нам даже сделать такое:

List<Number> numbers = new ArrayList<Integer>();

Рассмотрим абстрактный код (как пример):

List<Integer> integers = new ArrayList<Integer>();
List list = integers;
List<Number> numbers = integers; // error
numbers.add(4.5d);
Integer i = numbers.get(0); // error
Integer i = numbers.get(0); // ClassCastException

Ошибка выводится сразу в двух строках.

В первом:

java: incompatible types: java.util.List cannot be converted to java.util.List

Что в принципе и ожидалось, но даже если бы это сработало, то информация о типе в листе numbers стерлась бы (стирание типов). Следовательно, мы бы не смогли взять из этой коллекции Integer, а вместо этого получили бы ClassCastException.

Answer 2

ArrayList<T> implements List<T>, т.е. чтобы работал полиморфизм, нужно, чтобы тип и в ArrayList и в List был один и тот же. Для таких случаев есть generic wildcards.

List<? extends Comparable<BigDecimal>> l = new ArrayList<BigDecimal>();
READ ALSO
Как сделать плавную загрузку в ListView (Android)

Как сделать плавную загрузку в ListView (Android)

У меня есть горизонтальный progressBarИ в начале загрузки в ListView я устанавливаю значение progressBar

242
Помогите с реализацией

Помогите с реализацией

Я учусь работать на движке libgdx (и box2d соответственно) и хочу реализовать следующееУ меня есть персонаж, и я хочу, чтобы при его движении за ним...

119
Как заставить бота телеграм удалять свои же сообщения?

Как заставить бота телеграм удалять свои же сообщения?

Хочу, чтобы бот (TelegramLongPollingBot) периодически писал в беседу, что он онлайн и при этом удалял прошлое такое свое оповещениеКод для удаления старого...

166
не работают кнопки на java для андроид приложения

не работают кнопки на java для андроид приложения

не могу понять почему не работает, делаю приложение на андроид 44 в java, три кнопки и текст на экране, каждая кнопка меняет текст, но почему то не работает,...

191