"Agora, um tópico novo e interessante: curingas."

"Essencialmente, isso é algo como um padrão «*» que combina com qualquer coisa."

"Mas vamos começar do começo."

"Imagine que você tenha uma classe Warrior e um método que determina qual dos dois guerreiros é mais forte. Veja como isso pode parecer:"

Exemplo 1
class WarriorManager
{
 public static boolean fight(Warrior w1, Warrior w2)
 {
  return w1.power > w2.power;
 }
}
Exemplo de chamada de método
MagicWarrior mag = new MagicWarrior();
ArcherWarrior archer = new ArcherWarrior();

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

"MagicWarrior e ArcherWarrior herdam Warrior. "

"É um pouco simplista, mas, por exemplo, serve."

"OK."

"Agora, suponha que você decidiu fazer um método semelhante para a situação em que vários guerreiros entraram na briga."

Exemplo 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 
 }
}
Exemplo de chamada de método
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); // Compilation error!

"Mas aqui você encontra um erro de compilação e fica confuso sobre o que pode estar errado."

"O fato é que MagicWarrior herda Warrior , e os objetos MagicWarrior podem ser passados ​​para o método fight(Warrior, Warrior)."

"Mas List<MagicWarior> não herda List<Warrior> . Então, você não pode passá-lo lá!"

"O que você quer dizer com não herdar?"

"Quero dizer o seguinte: um é uma lista e o outro é uma lista, mas eles têm parâmetros de tipo."

"Você está certo. De alguma forma, não percebi isso imediatamente. Então, já existe uma solução para esse problema?"

"Sim. Você precisa usar uma estrutura mais complexa. É assim que fica:"

Exemplo 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 …
 }
}

"A parte «? estende o Guerreiro» significa «qualquer tipo que herda o Guerreiro»"

"Em outras palavras, agora você pode passar uma List<MagicWarrior> e uma List<ArcherWarrior>, e tudo funcionará."

"Isso é incrível. Quanto menos problemas, melhor."

"É assim que eu me sinto também."

"Mas e se eu não precisar de algo que herde Warrior? E se eu quiser passar qualquer List com qualquer parâmetro de tipo para o método? Isso é permitido?"

"Sim, existem duas formas de notação para fazer isso:"

List<? extends Object>
List<?>

"Ambos significam a mesma coisa, então a segunda versão é geralmente usada."

"Isso é tudo por hoje."

"Obrigado, Ellie. Eu realmente aprendi muito hoje."