— Нова цікава тема — 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<?>

Вони еквівалентні за змістом, тому зазвичай використовують другу.

У мене – все.

— Дякую, Дієго, дійсно дізнався сьогодні багато нового.