java genéricos super palavra-chave

Eu passei por esses tópicos

  • Genéricos ..? Super T
  • Genéricos limitantes com palavra-chave ‘super’

No entanto, eu ainda pareço meio que perdido com a super palavra-chave:

  1. Quando nós declaramos uma coleção assim:

     List list = null; list.add(new Integer(0));//this compiles list.add(new Object());//this doesn't compile 

    não deveria ser o oposto – nós temos uma lista que contém alguns objects (de tipo desconhecido) que são pais de Number . Então, Object deve caber (já que é o pai do Number ), e Integer não deveria. O oposto é o caso por algum motivo.

  2. Desde que tenhamos o seguinte código

     static void test(List param) { param.add(new Integer(2)); } public static void main(String[] args) { ArrayList sList = new ArrayList(); test(sList); //will never compile, however... } 

    É impossível compilar o código acima (e minha sanidade sugere que esse é o comportamento correto), mas a lógica básica pode provar o contrário:

    String is Object, Object is superclass of Number. So String should work.

    Eu sei que isso é loucura, mas essa não é a razão pela qual eles não permitiram construções do ? Se sim, então porque é permitido?

Alguém poderia me ajudar a restaurar a parte que falta dessa cadeia lógica?

O curinga limitado em List< ? super Number> List< ? super Number> pode capturar Number e qualquer um dos seus supertipos. Como Number extends Object implements Serializable , isso significa que os únicos tipos que são atualmente conversíveis em captura por List< ? super Number> List< ? super Number> são:

  • List
  • List
  • List

Observe que você pode add(Integer.valueOf(0)) a qualquer um dos tipos acima. no entanto, você NÃO PODE add(new Object()) a uma List ou a List , já que isso viola a regra de segurança de tipo genérico.

Por isso, NÃO é verdade que você pode add qualquer supertipo de Number a uma List< ? super Number> List< ? super Number> ; simplesmente não é como o curinga e o trabalho de conversão de captura limitados. Você não declara uma List< ? super Number> List< ? super Number> porque você pode querer adicionar um Object a ele (você não pode!); porque você deseja adicionar objects Number a ele (ou seja, é um “consumidor” de Number ) e simplesmente uma List é muito restritiva.

Referências

  • Perguntas frequentes sobre genéricos de Angelika Langer
    • O que é um curinga limitado?
    • Quando eu usaria um tipo com parâmetros curinga com um limite inferior? (“Quando um tipo parametrizado concreto seria muito restritivo.”)
    • Por que não há limite inferior para os parâmetros de tipo? (“Porque isso não faz sentido”)
  • JLS 5.1.10 Captura de Conversão

Veja também

  • Efetivo Java 2nd Edition , Item 28: Use curingas limitados para aumentar a flexibilidade da API
    • “PECS significa produtor- extends , consumidor super

Perguntas relacionadas

  • Muitos para listar, PECS, new Integer(0) vs valueOf , etc

Para a primeira parte, List se encheckbox na List< ? super Number> List< ? super Number> mas você não pode adicionar um Object a uma List . É por isso que você não pode adicionar um Object à List< ? super Number> List< ? super Number> .

Por outro lado, você pode adicionar todas as subclasss de Number ( Number included) à sua lista.

Para a segunda parte, String é um Object , mas String não é uma superclass de Number .

Se funcionasse assim, como toda class é uma subclass de Object , super não teria significado.


Vamos ver todos os casos possíveis com List< ? super Number> List< ? super Number> :


  • A lista passada é uma List
    • List funcionará
    • Object se encheckbox em < ? super Number> < ? super Number>
    • Você pode adicionar qualquer subtipo de Number a uma List
    • Mesmo que você também possa adicionar String , a única coisa de que você tem certeza é que você pode adicionar qualquer subclass de Number .

  • A lista passada é uma List :
    • List funcionará
    • Number se encheckbox em < ? super Number> < ? super Number>
    • Você pode adicionar qualquer subtipo de Number a uma List

  • A lista passada é uma List (ou qualquer subclass de Number ):
    • List não funciona
    • Inteiro é uma subclass de Number então é exatamente o que queremos evitar
    • Mesmo se um Integer couber em um Number você não poderá adicionar nenhuma subclass de Number em uma List (por exemplo, um Float )
    • super não significa uma subclass.

  • A lista passada é uma List (ou qualquer class que não estenda o Number nem na “super hierarquia” do Number (ou seja, Number e Object ):
    • List não funcionará
    • String não se encheckbox no Number “super hierarquia”
    • Mesmo se String se encheckbox em Object (que é uma superclass de Number ) você não teria certeza de poder adicionar um Number a uma List que contenha qualquer subclass de uma das superclasss de Number )
    • super não significa qualquer subclass de uma das superclasss, isso significa apenas uma das superclasss.

Como funciona ?

Você poderia dizer que, desde que você possa adicionar qualquer subclass de Number à sua List digitada, ela respeita a palavra super chave super .

Eu tive o mesmo problema. Eu acho que a syntax é a causa da confusão.

List< ? super Number> List< ? super Number> parece sugerir ” uma lista de coisas que são supertipos de Number “, mas o que realmente significa é ” uma lista de coisas que têm Number como seu supertipo “.

Depois que comecei a ler assim, cliquei.

List< ? super Number> List< ? super Number> significa que o tipo de referência da variável sugere que tenhamos uma lista de números, objects ou serializáveis.

A razão pela qual você não pode adicionar um object, é porque o compilador não sabe qual dessas classs estão na definição genérica do object instanciado real, portanto ele só permite que você passe número ou subtipos de número, como Double, Integer e em breve.

Vamos dizer que temos um método que retorna uma List< ? super Number> List< ? super Number> . A criação do object dentro do método é encapsulado a partir de nossa visão, nós simplesmente não podemos dizer se é algo assim:

List< ? super Number> returnValue = new LinkedList();

ou

List< ? super Number> returnValue = new ArrayList();

Portanto, o tipo genérico poderia ser Objeto ou Número. Em ambos os casos, poderíamos adicionar Number, mas somente em um caso poderíamos adicionar Object.

Você precisa distinguir entre o tipo de referência e o tipo de object real nessa situação.

List< ? super Number> List< ? super Number> é uma List onde podemos implicitamente converter cada Number em seu super tipo AncestorOfNumber .

Considere isto: Qual tipo genérico precisa ser ???? no exemplo a seguir?

 InputStream mystream = ...; void addTo(List< ????> lsb) { lsb.add(new BufferedInputStream(mystream)); } List lb = new ArrayList<>(); List li = new ArrayList<>(); List lo = new ArrayList<>(); ... { addTo(lb); addTo(li); addTo(lo); } 

A resposta: ???? é qualquer coisa para a qual podemos lançar BufferedInputStream , que é isso mesmo ou um dos seus antepassados ? super BufferedInputStream ? super BufferedInputStream

Eu não entendi por um tempo. Muitas das respostas aqui e as outras perguntas mostram especificamente quando e onde certos usos são erros, mas não tanto por quê.

É assim que finalmente consegui. Se eu tiver uma function que adicione Number s a uma List , talvez queira incluí-los do tipo MySuperEfficientNumber que é minha própria class customizada que implementa Number (mas não é uma subclass de Integer ). Agora, o chamador pode não saber nada sobre MySuperEfficientNumber , mas, desde que saiba tratar os elementos adicionados à lista como nada mais específico que Number , eles ficarão bem.

Se eu declarasse meu método como:

 public static void addNumbersToList(List< ? extends Number> numbers) 

Em seguida, o chamador poderia passar em uma List . Se meu método adicionasse um MySuperEfficientNumber ao final dos numbers , o chamador não teria mais uma List de Integer e o seguinte código não funcionaria:

 List numbers = new ArrayList(); addNumbersToList(numbers); // The following would return a MySuperEfficientNumber not an Integer Integer i = numbers.get(numbers.size()-1) 

Obviamente, isso não pode funcionar. E o erro estaria dentro do método addNumbersToList . Você teria algo como:

 The method add... is not applicable for the arguments (MySuperEfficientNumber) 

Como os numbers podem ser qualquer tipo específico de Number , não necessariamente algo com o qual MySuperEfficientNumber é compatível. Se eu invertesse a declaração para usar super , o método seria compilado sem erro, mas o código do chamador falharia com:

 The method addNumbersToList(List< ? super Number>)... is not applicable for the arguments (List) 

Porque meu método está dizendo: “Não pense que a sua List pode ser de algo mais específico do que o Number . Eu posso adicionar todos os tipos de Number estranhos à lista, você terá que lidar com isso. Se você quiser Pense neles como algo ainda mais geral do que o Number – como o Object – tudo bem, eu garanto que eles serão pelo menos os Number s, mas você pode tratá-los mais geralmente se quiser. ”

Considerando que extends está dizendo: “Eu realmente não me importo com o tipo de List você me dá, contanto que cada elemento seja pelo menos um Number . Pode ser qualquer Number , até mesmo seu próprio número estranho, personalizado e inventado. Desde que eles implementem essa interface, estamos bem. Eu não vou adicionar nada à sua lista, já que não sei qual tipo de concreto você está usando. ”