"Oi! Vou continuar a aula de Ellie sobre genéricos. Pronto para ouvir?"
"Sim."
"Então vamos começar."
"A primeira coisa que você precisa saber é que os métodos de uma classe também podem ter seus próprios parâmetros de tipo."
"Eu sei."
"Não, quero dizer especificamente seus próprios parâmetros de tipo: "
class Calculator
{
T add(T a, T b); // Add
T sub(T a, T b); // Subtract
T mul(T a, T b); // Multiply
T div(T a, T b); // Divide
}
"Esses parâmetros de tipo pertencem especificamente aos métodos. A classe não tem parâmetros. Você pode até mesmo declarar esses métodos estáticos e chamá-los sem um objeto."
"Entendo. O objetivo dos parâmetros de tipo nos métodos é o mesmo das classes?"
"Sim. Mas há algo novo."
"Como você já sabe, você pode usar um curinga na declaração de tipo. Então imagine a seguinte situação:"
public void doSomething(List<? extends MyClass> list)
{
for(MyClass object : list)
{
System.out.println(object.getState()); // Everything works well here.
}
}
"Mas e se quisermos adicionar um novo item à coleção:"
public void doSomething(List<? extends MyClass> list)
{
list.add(new MyClass()); // Error!
}
"O problema é que, em geral, o método doSomething pode receber uma lista cujos elementos não são objetos MyClass, mas sim objetos de qualquer subclasse de MyClass. Mas você não pode adicionar objetos MyClass a essa lista!"
"Ah. Então, o que pode ser feito sobre isso?"
"Nada. Nesta situação, você não pode fazer nada. Mas isso deu aos criadores de Java algo em que pensar. E eles criaram uma nova palavra-chave: super ."
"A sintaxe parece quase a mesma:"
List<? super MyClass> list
Mas há uma distinção importante entre extends e super.
"«? estende T» significa que a classe deve ser descendente de T."
"«? super T» significa que a classe deve ser um ancestral de T."
"Caramba. Então, onde isso é usado?"
"«? super T» é usado quando um método envolve adicionar a uma coleção de T objetos. Nesse caso, pode ser uma coleção de T objetos ou qualquer ancestral de T."
"Ah. O objeto AT pode ser atribuído a uma variável de referência cujo tipo é qualquer um dos ancestrais de T"
"Honestamente, essa abordagem não é usada com muita frequência. Além do mais, ela tem uma falha. Por exemplo:"
public void doSomething(List<? super MyClass> list)
{
for(MyClass object : list) // Error!
{
System.out.println(object.getState());
}
}
public void doSomething(List<? super MyClass> list)
{
list.add(new MyClass()); // Everything works well here.
}
"Agora o primeiro exemplo não funciona."
"Como a lista pode até ser uma List<Object> (Object é a superclasse mais importante de MyClass), estamos essencialmente escrevendo o seguinte código inválido:"
List<Object> list;
for(MyClass object : list) // Error!
{
System.out.println(object.getState());
}
"Entendo. Obrigado pela lição interessante."
"De nada."
GO TO FULL VERSION