Alguém pode explicar o que faz mean e quando deve ser usado e como esta construção deve cooperar com e ?

Eu estou usando genéricos há muito tempo, mas eu nunca usei construção como List List .

O que isso significa? Como usá-lo? Como se parece após o apagamento?

Eu também me pergunto: é algo padrão em programação genérica (programação de template?) Ou é apenas uma ‘invenção’ java? C #, por exemplo, permite construções semelhantes?

Essa construção é usada quando você deseja consumir itens de uma coleção em outra coleção. Por exemplo, você tem uma Stack genérica e deseja adicionar um método popAll que usa um parâmetro Collection como e insere todos os itens da pilha nela. Por bom senso, esse código deve ser legal:

 Stack numberStack = new Stack(); Collection objects = ... ; numberStack.popAll(objects); 

mas ele compila apenas se você definir popAll assim:

 // Wildcard type for parameter that serves as an E consumer public void popAll(Collection dst) { while (!isEmpty()) dst.add(pop()); } 

O outro lado da moeda é que pushAll deve ser definido assim:

 // Wildcard type for parameter that serves as an E producer public void pushAll(Iterable src) { for (E e : src) push(e); } 

Atualização: Josh Bloch propaga este mnemônico para ajudá-lo a lembrar qual tipo de caractere curinga usar:

PECS significa produtor-se estende, consumidor-super .

Para mais detalhes, veja Effective Java 2nd Ed., Item 28 .

Isso é chamado de “curinga delimitada”. Está muito bem explicado no tutorial oficial .

Como afirmado no tutorial, você sabe que a lista contém objects de exatamente um subtipo de T

Por exemplo, List List pode conter apenas Integer s ou somente Long s, mas não ambos.

Essas coisas são conhecidas, na teoria de tipos, como variância , com sendo uma notação co-variante, e sendo uma notação contra-variante. A explicação mais simples é essa ? pode ser substituído por qualquer tipo estendendo T na notação co-variante, e ? pode ser substituído por qualquer tipo que T se estenda na contra-variante.

Usar co e contra-variância é muito mais difícil do que parece inicialmente, particularmente porque a variância “alterna” dependendo da posição.

Um exemplo simples seria uma class de function. Digamos que você tenha uma function que receba um A e retorne um B A notação correta para isso seria dizer que A é contra-variante e B os co-variante. Para entender melhor como isso é o caso, vamos considerar um método – vamos chamá-lo de g – que recebe essa class de function hipotética, onde f deve receber um Arc2D e retornar uma Shape .

Dentro de g , esse f é chamado de passar um Arc2D e o valor de retorno é usado para inicializar uma Area (que espera uma Shape ).

Agora, suponha que f você passe receba qualquer Shape e retorne um Rectangle2D . Como um Arc2D é também um Shape , então g não obterá um erro passando um Arc2D para f , e como um Rectangle2D também é um Shape , ele pode ser passado para o construtor de Area .

Se você tentar inverter qualquer um dos desvios ou trocar os tipos esperado e real naquele exemplo, verá que ele falha. Eu não tenho tempo agora para escrever este código, e meu Java está bastante enferrujado, de qualquer forma, mas eu vou ver o que posso fazer depois – se ninguém tiver a gentileza de fazer isso primeiro.

O Java Generics FAQ tem uma boa explicação sobre os genéricos Java. Verifique a pergunta O que é um curinga limitado? o que explica o uso do constructo “? super T” com bons detalhes.