Então pessoal, tava vendo mais a fundo aqui generics, mas não achei muita coisa aqui no forum (topicos e tal). Bem, mexo a um tempinho ja com generics, mas sempre o basico e tal, nunca precisei usar os curinhas (?). Bem dei uma olhada e fiz um exemplo, para eu deixar aqui e estudar/lembrar já que é algo que não uso diariamente (os coringas - ?). Queria que vocês dessem uma olhada se minhas conclusões estão corretas, e se possivel me darem uns exemplos de quando vocês sentiram necessidade de usar <? super XXX>, eu geralmente uso <T extends XXX>, no maximo mesmo, usei um <? extends XXX> mas nunca <? super XXX>
Segue meu código de exemplo (deem uma lida nos meus comentários para eu saber se é assim como estou pensando)
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
//informações de http://www.argonavis.com.br/cursos/java/j100/tiger.html#j5-genericos
public class Generics
{
public class A implements Serializable
{
public int a = 1;
}
public class B extends A
{
public int b = 2;
}
public class C extends B
{
public int c = 3;
}
public static void main(String[] args)
{
new Generics().a();
}
public void a()
{
// teste1(new ArrayList<A>()); // "A" não extende "B" (erro)
teste1(new ArrayList<B>()); // "B" eh "B"
teste1(new ArrayList<C>()); // "C" extende "B"
// teste2(new ArrayList<A>()); // "A" não extende "B" (erro)
teste2(new ArrayList<B>()); // "B" eh "B"
teste2(new ArrayList<C>()); // "C" extende "B"
teste4(new ArrayList<Object>()); // "Object" eh super de "A"
teste4(new ArrayList<Serializable>()); // "A" implementa Serializable
teste4(new ArrayList<A>()); // "A" eh "A"
// teste4(new ArrayList<B>()); // "B" não eh super de "A" (erro)
// teste4(new ArrayList<C>()); // "C" não eh super de "A" (erro)
teste3(new ArrayList<B>(), new B()); // "B" extends "B"
teste3(new ArrayList<B>(), new C()); // "C" extends "B"
teste3(new ArrayList<C>(), new C()); // "C" extends "B"
// teste3(new ArrayList<C>(), new B()); //porque a lista "C" não aceita o tipo "B" (erro)
}
/**
* Aceita qualquer lista de objetos que extendem "B", ou seja "C" ou "B". Por isso que ao remover o objeto ele é um "B", pois pode ser uma lista de
* qualquer coisa abaixo de "B" (o que sera no minimo um B, garantido). E para incluir ele não sabe qual o tipo, pois o tipo é um curinga (?) que
* extende "B" e ateh onde o ? chega eh desconhecido, poderia ser até "C", nesse caso não poderia inserir "B", ou o ? poderia ser mais baixo que
* "C", então não poderia incluir nem "C" nem "B", enfim, não se sabe o que é ?, então não pode incluir. Como se fosse uma lista de objetos
* desconhecidos abaixo de "B"..
*/
public void teste1(List< ? extends B> col)
{
B x = col.get(1);
// col.add(new C()); //não sei que nivel incluir (erro)
}
/**
* Idem ao teste1(), porem aqui eu posso incluir um Objecto do tipo T (é o delimitador de ateh onde chega o coringa), com isso eu poderia receber
* por parametro um objeto do tipo T e incluir. (ver teste3)
*/
public <T extends B> void teste2(List<T> col)
{
B x1 = col.remove(1);
T x2 = col.remove(1);
// col.add(new C()); //não pode incluir (erro)
}
/**
* Aqui o add funciona, mas é porque eu tenho um delimitador do "?" que é T.
*/
public <T extends B> void teste3(List<T> col, T obj)
{
col.add(obj);
}
/**
* Lista de objetos que forem super de "A", ou seja, "Object", "A" ou qualquer coisa que "A" extende ou implementa (contrario do extends), por isso
* para remover, o método devolve um objeto do tipo "Object". Para incluir a abordagem é diferente, vai incluir qualquer objeto "A" ou que tenha
* como super "A", ou seja "B" ou "C", porque diferente do <? extends A>, este eu sei até onde chega o curinga, no máximo até "A", então incluo
* "A". Com isso, da para receber uma Lista de "Object" (que é super de "A") e incluir objetos "B" ou "C" que são extends de "A", ao remover, o
* casting para "B" ou "C" funciona normalmente.
*/
public void teste4(List< ? super A> col)
{
// col.add(new Object()); // erro, Object não tem A como super.
col.add(new A());
col.add(new B());
// casting funciona normal
A z1 = (A) col.get(0); // retorna Object
B z2 = (B) col.get(1); // retorna Object
System.out.println(z1.a);
System.out.println(z2.b);
}
}