Eu não sei como entender o tipo de caractere curinga em Java

5

Estou lendo o Core Java (9ª edição) de Cay S. Horstmann e Gary Cornell. Depois de fazer um esforço, ainda não consigo entender o ? super gerente . Aqui estão alguns materiais relacionados a esta questão.

public class Pair<T> {
    private T first;
    private T second;

    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    public void setFirst(T first) {
        this.first = first;
    }

    public void setSecond(T second) {
        this.second = second;
    }

    public T getFrist() {
        return this.first;
    }

    public T getSecond() {
        return this.second;
    }
}

O Manager herda de Employee e Executive herdados de Manager . Pair tem os seguintes métodos:

void setFirst(? super Manager)
? super Manager getFirst()

Desde ? Super Manager denota qualquer supertipo de Manager , porque eu não posso chamar o método setFirst com Employee (é óbvio que Employee é o supertipo do Manager), mas apenas com o tipo Manager ou um subtipo como Executive (mas o Executive é o subtipo de Manager, não um supertipo de Manager)?

    
por Lucas Li 15.06.2014 / 04:47
fonte

2 respostas

2

Pode-se ler e reiterá-lo repetidas vezes - como já foi várias vezes. Em um comentário à sua pergunta, Philipp já vinculado a uma pergunta no Stackoverflow que tenta respondê-la . Para mim, a explicação do Tio Bob resolveu o problema.

Ele escreve (ao lado de muitas outras coisas boas):

A List<? super Shape> is a list into which you may add Shapes. Another way to think of this is that the type <? super T> is an unknown type that T can substitute for. You may have to read that several times before you understand it. I certainly did. So here's yet another way to think about it. The type <? super T> is a type that T is derived from. It is a base class of T. Clearly if D is derived from B then you can put D instances into a List<B>. Likewise, since T derives from <? super T>, you can put T instances into a List<? super T>. Follow? No? Neither did I for awhile. It takes a bit of getting used to.

O que isso significa, no final, é que sua suposição de que você poderia colocar super-tipos de Manager em seu List<? super Manager> está errada. Não é isso que se entende aqui. A palavra-chave super soluciona o problema de não ser possível inserir itens em locais genéricos enquanto você conseguiu sair (com extends ).

Imagine dois pares, um que estende o gerente, um que "supere":

Pair<? extends Manager> subPair = new Pair<Manager>();
Pair<? super Manager> superPair = new Pair<Manager>();

O que você pode nunca fazer é inserir um Employee em qualquer um destes:

subPair.setFirst(new Employee());
superPair.setFirst(new Employee());

Se você quiser gerentes, os funcionários nunca serão suficientes. E é pior: você não pode inserir um Executive no seu subPair , mesmo que Executive extends Manager . Não irá compilar:

subPair.setFirst(new Executive());

Editar: Por que é que? Bem, seu genérico subPair sempre se refere a alguns "explícitos" Pair , Pair<Manager> neste caso. Pode muito bem ter se referido a um Pair<CoManager> (com CoManager extends Manager ). O Java não saberá o tipo explícito que é realmente usado e, portanto, não poderá permitir inserções.

Mas super vem para o resgate. Com super você pode inserir Gerentes e seus subtipos no seu Pair . E é para isso que o super é: Inserindo.

superPair.setFirst(new Executive());

Edit: Por que isso funciona? Embora extends garanta que você algum digite que implementa (ou deriva de) Manager , super garante qualquer tal tipo. Então, enquanto com extends você obtém um tipo específico com (pelo menos) a interface Manager , com super você pode inserir qualquer tipo com o Manager interface.

E para a foto maior, eu realmente sugiro ler o artigo do tio Bob.

    
por 15.06.2014 / 12:26
fonte
0

A diferença parece ser o propósito da sua variável.

Se você usar uma variável do tipo Pair para ler, use Pair<? extends Manager> Neste caso, ao chamar um método de par que retorne algo parametrizado, você terá o benefício do tipo seguro. Mas você quase não pode escrever nada nele, sempre um erro de compilação.

Por outro lado, se você usar uma variável do tipo Pair para escrever, então você usa %código%. Nesse caso, ao chamar um método de Pair<? super Manager> type que recebe uma variável parametrizada de tipo (ou subtipo) de Pair<> , você tem o tipo seguro.

Honestamente, não vejo a diferença entre Manager e Pair<? super Manager> , exceto quando você usa Pair<Manager>  os métodos de leitura em Par < > retorna o objeto java genérico (ou seja, não é seguro para leitura, o tipo de compilador desencoraja a leitura neste caso)

Acho que vê-lo como ler e escrever assim é mais fácil.

Agora, voltemos ao motivo pelo qual você não pode escrever um objeto Pair<? super Manager> no seu Employee . Isso é porque Pair<? super Manager> é na verdade um tipo que estende algum supertipo desconhecido de <? super Manager> . E como é desconhecido, você não sabe se Manager é realmente um subtipo desse tipo desconhecido.

Ainda mais concreto: digamos que Employee também implemente uma interface Manager . Então IManager pode ser um objeto <? super Manager> e agora IManager não é uma substituição válida de Employee (porque não é um subtipo de IManager ). Nesse caso, qualquer subtipo de IManager pode ser uma substituição porque será um subtipo de qualquer supertipo desconhecido de Manager . Você pode chamar Manager aqui.

    
por 15.06.2014 / 08:34
fonte

Tags