Generics - coringas

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&#58;//www.argonavis.com.br/cursos/java/j100/tiger.html#j5-genericos 
public class Generics
&#123;
   public class A implements Serializable
   &#123;
      public int a = 1;
   &#125;

   public class B extends A
   &#123;
      public int b = 2;
   &#125;

   public class C extends B
   &#123;
      public int c = 3;
   &#125;

   public static void main&#40;String&#91;&#93; args&#41;
   &#123;
      new Generics&#40;&#41;.a&#40;&#41;;
   &#125;

   public void a&#40;&#41;
   &#123;

      // teste1&#40;new ArrayList&lt;A&gt;&#40;&#41;&#41;; // &quot;A&quot; não extende &quot;B&quot; &#40;erro&#41;
      teste1&#40;new ArrayList&lt;B&gt;&#40;&#41;&#41;; // &quot;B&quot; eh &quot;B&quot;
      teste1&#40;new ArrayList&lt;C&gt;&#40;&#41;&#41;; // &quot;C&quot; extende &quot;B&quot;

      // teste2&#40;new ArrayList&lt;A&gt;&#40;&#41;&#41;; // &quot;A&quot; não extende &quot;B&quot; &#40;erro&#41;
      teste2&#40;new ArrayList&lt;B&gt;&#40;&#41;&#41;; // &quot;B&quot; eh &quot;B&quot;
      teste2&#40;new ArrayList&lt;C&gt;&#40;&#41;&#41;; // &quot;C&quot; extende &quot;B&quot;

      teste4&#40;new ArrayList&lt;Object&gt;&#40;&#41;&#41;; // &quot;Object&quot; eh super de &quot;A&quot;
      teste4&#40;new ArrayList&lt;Serializable&gt;&#40;&#41;&#41;; // &quot;A&quot; implementa Serializable
      teste4&#40;new ArrayList&lt;A&gt;&#40;&#41;&#41;; // &quot;A&quot; eh &quot;A&quot;
      // teste4&#40;new ArrayList&lt;B&gt;&#40;&#41;&#41;; // &quot;B&quot; não eh super de &quot;A&quot; &#40;erro&#41;
      // teste4&#40;new ArrayList&lt;C&gt;&#40;&#41;&#41;; // &quot;C&quot; não eh super de &quot;A&quot; &#40;erro&#41;

      teste3&#40;new ArrayList&lt;B&gt;&#40;&#41;, new B&#40;&#41;&#41;; // &quot;B&quot; extends &quot;B&quot;
      teste3&#40;new ArrayList&lt;B&gt;&#40;&#41;, new C&#40;&#41;&#41;; // &quot;C&quot; extends &quot;B&quot;
      teste3&#40;new ArrayList&lt;C&gt;&#40;&#41;, new C&#40;&#41;&#41;; // &quot;C&quot; extends &quot;B&quot;
      // teste3&#40;new ArrayList&lt;C&gt;&#40;&#41;, new B&#40;&#41;&#41;; //porque a lista &quot;C&quot; não aceita o tipo &quot;B&quot; &#40;erro&#41;

   &#125;

   /**
    * Aceita qualquer lista de objetos que extendem &quot;B&quot;, ou seja &quot;C&quot; ou &quot;B&quot;. Por isso que ao remover o objeto ele é um &quot;B&quot;, pois pode ser uma lista de
    * qualquer coisa abaixo de &quot;B&quot; &#40;o que sera no minimo um B, garantido&#41;. E para incluir ele não sabe qual o tipo, pois o tipo é um curinga &#40;?&#41; que
    * extende &quot;B&quot; e ateh onde o ? chega eh desconhecido, poderia ser até &quot;C&quot;, nesse caso não poderia inserir &quot;B&quot;, ou o ? poderia ser mais baixo que
    * &quot;C&quot;, então não poderia incluir nem &quot;C&quot; nem &quot;B&quot;, enfim, não se sabe o que é ?, então não pode incluir. Como se fosse uma lista de objetos
    * desconhecidos abaixo de &quot;B&quot;..
    */
   public void teste1&#40;List&lt; ? extends B&gt; col&#41;
   &#123;
      B x = col.get&#40;1&#41;;
      // col.add&#40;new C&#40;&#41;&#41;; //não sei que nivel incluir &#40;erro&#41;
   &#125;

   /**
    * Idem ao teste1&#40;&#41;, porem aqui eu posso incluir um Objecto do tipo T &#40;é o delimitador de ateh onde chega o coringa&#41;, com isso eu poderia receber
    * por parametro um objeto do tipo T e incluir. &#40;ver teste3&#41;
    */
   public &lt;T extends B&gt; void teste2&#40;List&lt;T&gt; col&#41;
   &#123;
      B x1 = col.remove&#40;1&#41;;
      T x2 = col.remove&#40;1&#41;;
      // col.add&#40;new C&#40;&#41;&#41;; //não pode incluir &#40;erro&#41;
   &#125;

   /**
    * Aqui o add funciona, mas é porque eu tenho um delimitador do &quot;?&quot; que é T.
    */
   public &lt;T extends B&gt; void teste3&#40;List&lt;T&gt; col, T obj&#41;
   &#123;
      col.add&#40;obj&#41;;
   &#125;

   /**
    * Lista de objetos que forem super de &quot;A&quot;, ou seja, &quot;Object&quot;, &quot;A&quot; ou qualquer coisa que &quot;A&quot; extende ou implementa &#40;contrario do extends&#41;, por isso
    * para remover, o método devolve um objeto do tipo &quot;Object&quot;. Para incluir a abordagem é diferente, vai incluir qualquer objeto &quot;A&quot; ou que tenha
    * como super &quot;A&quot;, ou seja &quot;B&quot; ou &quot;C&quot;, porque diferente do &lt;? extends A&gt;, este eu sei até onde chega o curinga, no máximo até &quot;A&quot;, então incluo
    * &quot;A&quot;. Com isso, da para receber uma Lista de &quot;Object&quot; &#40;que é super de &quot;A&quot;&#41; e incluir objetos &quot;B&quot; ou &quot;C&quot; que são extends de &quot;A&quot;, ao remover, o
    * casting para &quot;B&quot; ou &quot;C&quot; funciona normalmente.
    */
   public void teste4&#40;List&lt; ? super A&gt; col&#41;
   &#123;
      // col.add&#40;new Object&#40;&#41;&#41;; // erro, Object não tem A como super.
      col.add&#40;new A&#40;&#41;&#41;;
      col.add&#40;new B&#40;&#41;&#41;;

      // casting funciona normal
      A z1 = &#40;A&#41; col.get&#40;0&#41;; // retorna Object
      B z2 = &#40;B&#41; col.get&#40;1&#41;; // retorna Object
      System.out.println&#40;z1.a&#41;;
      System.out.println&#40;z2.b&#41;;
   &#125;

&#125;