Generics: wildcards

Открыта

— Новая интересная тема — wildcards.

По смыслу, это что-то вроде шаблона «*», который совпадает с чем угодно.

Но давай начнем издалека.

Представь, что у тебя есть класс «Warrior(Воин)» и метод, который вычисляет, какой из двух воинов сильнее. Вот как, например, это могло бы выглядеть:

Пример 1
class WarriorManager
{
 public static boolean fight(Warrior w1, Warrior w2)
 {
  return w1.power > w2.power;
 }
}
Пример вызова
MagicWarrior mag = new MagicWarrior();
ArcherWarrior archer = new ArcherWarrior();

boolean isMagicCooler = WarriorManager.fight(mag, archer);

MagicWarrior и ArcherWarrior – это классы-наследники от Warrior.

Немного простовато, но для примера сойдет.

— Ок.

— И вот допустим, ты решил сделать аналогичный метод, где уже дерутся воины стенка на стенку.

Пример 1
class WarriorManager
{
 public static boolean fight(Warrior w1, Warrior w2)
 {
  return w1.power > w2.power;
 }

 public static boolean fight(List<Warrior> w1, List<Warrior> w2)
 {
  return …
 }
}
Пример вызова
ArrayList<MagicWarrior> magi = new ArrayList<MagicWarrior>();
for(int i=0;i<10;i++)
 magi.add(new MagicWarrior());

ArrayList<ArcherWarrior> archers = new ArrayList<ArcherWarrior>();
for(int i=0;i<10;i++)
 archers.add(new ArcherWarrior());

boolean isMagicCooler = WarriorManager.fight(magi, archers); //ошибка компиляции!

И вот тут ты встречаешь ошибку компиляции и недоумеваешь, а что не так-то?

Все дело в том, что MagicWarrior – это наследник Warrior и его объекты можно передавать в метод fight(Warrior, Warrior)

А вот List<MagicWarrior> — это не наследник List<Warrior>. И передавать его туда нельзя!

— Как это не наследник?

— А вот так. То List и то – List. Пусть и с параметрами.

— Да, а я как-то сразу не обратил внимание. И что, есть уже решение этой проблемы?

— Ага. Для этого используется более сложная конструкция. Выглядит это так:

Пример 1
class WarriorManager
{
 public static boolean fight(Warrior w1, Warrior w2)
 {
  return w1.power > w2.power;
 }

 public static boolean fight(List<? extends Warrior> w1, List<? extends Warrior> w2)
 {
  return …
 }
}

«? extends Warrior» обозначает «любой тип, унаследованный от Warrior ».

Т.е. туда можно передать список List<MagicWarrior> и список List<ArcherWarrior>, и все будет работать.

— Так это же отлично. Чем меньше всяких таких проблем, тем лучше.

— Так и я о том же.

— А если мне не нужен наследник Warrior? Что если я хочу, чтобы в метод можно было передать любой List с любым параметром? Так можно?

— Да, для описания этой ситуации существует две записи:

List<? extends Object>
List<?>

Они эквивалентны по смыслу, поэтому обычно используют вторую.

У меня – все.

— Спасибо, Элли, действительно узнал сегодня много нового.

Комментарии (12)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Underdante
Уровень 69
23 апреля, 16:56
почему нельзя написать
public static boolean fight(List<T extends Warrior> w1, List<T extends Warrior> w2)
{
 return …
}
я не понял
Руслан
Уровень 48
18 сентября 2025, 16:13
мда лекция банчик конечно вот есть такая штука пользуйтесь а зачем как работает это уже сами найдете
Родион
Уровень 113
30 мая 2025, 17:08
тот, кто читает этот комментарий, знай, что если тебе кажется, что примеры непонятные и в них используются приемы которых тебе еще не объясняли, то тебе не кажется
Виктор Ш
Уровень 3
17 марта 2025, 17:34
Примеры понял с трудом. Пойду чат допрашивать
Вячеслав
Уровень 40
27 декабря 2024, 06:08
На мой взгляд, если примеры описывались бы полностью, было бы понятнее
Ольга
Уровень 24
Expert
24 апреля 2022, 09:46
Я так и не поняла, кто сильней МАГ или Лучник?)))
Андрей Федоров студент Expert
20 июня 2022, 10:29
что вкуснее: "мёд или малина?"
Greg
Уровень 108
Expert
5 октября 2022, 11:14
Земляника.
jvatechsBackend Developer в Ищу стажировкуExpert
12 февраля 2023, 22:53
Однозначно, что маг.
Павел Software Developer
18 января 2024, 07:57
возможность создать фаерболл круче возможности пустить стрелу
Рубен
Уровень 80
10 мая 2024, 13:44
тот у кого дробовик
11 апреля 2022, 07:43
как-то мудрено все конечно описано..и примеры запутанные, для новичка все таки сложновато:)