— Новая интересная тема — wildcards.
По смыслу, это что-то вроде шаблона «*», который совпадает с чем угодно.
Но давай начнем издалека.
Представь, что у тебя есть класс «Warrior(Воин)» и метод, который вычисляет, какой из двух воинов сильнее. Вот как, например, это могло бы выглядеть:
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.
Немного простовато, но для примера сойдет.
— Ок.
— И вот допустим, ты решил сделать аналогичный метод, где уже дерутся воины стенка на стенку.
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. Пусть и с параметрами.
— Да, а я как-то сразу не обратил внимание. И что, есть уже решение этой проблемы?
— Ага. Для этого используется более сложная конструкция. Выглядит это так:
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<?>
Они эквивалентны по смыслу, поэтому обычно используют вторую.
У меня – все.
— Спасибо, Элли, действительно узнал сегодня много нового.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ