Duvido que haja alguma diferença. Eu acho que é apenas um nome para esse parâmetro de tipo. E o último é válido?
CodesInChaos
Respostas:
231
Bem, não há diferença entre os dois primeiros - eles estão apenas usando nomes diferentes para o parâmetro type ( Eou T).
A terceira não é uma declaração válida - ?é usada como curinga que é usada ao fornecer um argumento de tipo , por exemplo, List<?> foo = ...significa que foose refere a uma lista de algum tipo, mas não sabemos o que.
Tudo isso é genérico , que é um tópico bastante grande. Você pode aprender sobre isso através dos seguintes recursos, embora haja mais disponíveis, é claro:
Parece que o link para o PDF está quebrado. Encontrei o que parece ser uma cópia aqui , mas não posso estar 100% certo, pois não sei como era o original.
John
2
@ John: Sim, é esse. Irá editar um link em, quer que um ou um Oracle um ...
Jon Skeet
Existe algo além de T, E e? usado em genéricos? Se sim, o que são e o que significam?
sofs1
1
@ sofs1: Não há nada de especial Te E- eles são apenas identificadores. Você poderia escrever KeyValuePair<K, V>por exemplo. ?tem um significado especial.
precisa
215
É mais convenção do que qualquer outra coisa.
T deve ser um tipo
Edeve ser um elemento ( List<E>: uma lista de elementos)
Ké a chave (em a Map<K,V>)
V é Value (como valor de retorno ou valor mapeado)
Eles são totalmente intercambiáveis (não obstante os conflitos na mesma declaração).
A letra entre <> é apenas um nome. O que você descreve em sua resposta são apenas convenções. Nem precisa ser uma única letra maiúscula; você pode usar qualquer nome que desejar, assim como pode dar classes, variáveis etc. qualquer nome que desejar.
Você não explicou o ponto de interrogação. Votado.
Shinzou 7/05/19
129
As respostas anteriores explicam os parâmetros de tipo (T, E etc.), mas não explicam o caractere curinga "?" Ou as diferenças entre eles; portanto, abordarei isso.
Primeiro, só para esclarecer: os parâmetros curinga e tipo não são os mesmos. Onde os parâmetros de tipo definem um tipo de variável (por exemplo, T) que representa o tipo de um escopo, o curinga não: o curinga apenas define um conjunto de tipos permitidos que você pode usar para um tipo genérico. Sem qualquer delimitação ( extendsou super), o curinga significa "use qualquer tipo aqui".
O curinga sempre se encontra entre colchetes angulares e só tem significado no contexto de um tipo genérico:
publicvoid foo(List<?> listOfAnyType){...}// pass a List of any type
Nunca
public<?>? bar(? someType){...}// error. Must use type params here
Fica mais confuso onde eles se sobrepõem. Por exemplo:
List<T> fooList;// A list which will be of type T, when T is chosen.// Requires T was defined above in this scopeList<?> barList;// A list of some type, decided elsewhere. You can do// this anywhere, no T required.
Há muita sobreposição no que é possível com as definições de método. A seguir, são funcionalmente idênticos:
Então, se houver sobreposição, por que usar um ou outro? Às vezes, é honestamente apenas estilo: algumas pessoas dizem que se você não precisar de um parâmetro de tipo, você deve usar um curinga apenas para tornar o código mais simples / mais legível. Uma diferença principal que expliquei acima: parâmetros de tipo definem uma variável de tipo (por exemplo, T) que você pode usar em outro lugar no escopo; o curinga não. Caso contrário, existem duas grandes diferenças entre os parâmetros de tipo e o curinga:
Parâmetros de tipo podem ter várias classes delimitadoras; o curinga não pode:
O curinga pode ter limites mais baixos; params de tipo não podem:
publicvoid bar(List<?superInteger> list){...}
No exemplo acima, List<? super Integer>define Integercomo um limite inferior no curinga, o que significa que o tipo de Lista deve ser Inteiro ou um supertipo de Inteiro. O limite de tipo genérico está além do que quero abordar em detalhes. Em resumo, permite definir quais tipos podem ser de um tipo genérico. Isso torna possível o tratamento de genéricos polimorficamente. Por exemplo, com:
publicvoid foo(List<?extendsNumber> numbers){...}
Você pode passar um List<Integer>, List<Float>, List<Byte>, etc para numbers. Sem delimitação de tipos, isso não funcionará - é assim que os genéricos são.
Finalmente, aqui está uma definição de método que usa o curinga para fazer algo que eu acho que você não pode fazer de outra maneira:
numberSuperpode ser uma lista de números ou qualquer supertipo de número (por exemplo, List<Object>) e elemdeve ser um número ou qualquer subtipo. Com todas as delimitações, o compilador pode ter certeza de que .add()é tipicamente seguro .
"public void foo (List <? extends Number> numbers) {...}" deve "extends" ser "super"?
1a1a11a 06/06/2015
1
Não. O objetivo desse exemplo é mostrar uma assinatura que suporte polimorficamente uma lista de números e os subtipos de número. Para isso, você usa "estende". Ou seja, "me passe uma lista de números ou qualquer coisa que estenda o número" (lista <Integer>, lista <Float>, qualquer que seja). Um método como esse pode percorrer a lista e, para cada elemento, "e", executar, por exemplo, e.floatValue (). Não importa que subtipo (extensão) de Número você passe - você sempre poderá ".floatValue ()", porque .floatValue () é um método de Number.
precisa
No seu último exemplo, "List <? Super Number>" poderia simplesmente ser "List <Number>", pois o método não permite nada mais genérico.
jessarah
@jessarah nope. Talvez meu exemplo não esteja claro, mas mencionei no exemplo que adder () poderia receber uma List <Object> (Object é uma superclasse de Number). Se você quiser fazer isso, deve ter a assinatura "List <? Super Number>". Esse é exatamente o ponto de "super" aqui.
Hawkeye Parker
2
Essa resposta é muito boa para explicar as diferenças entre caracteres curinga e parâmetros de tipo; deve haver uma pergunta dedicada a essa resposta. Ultimamente, estou me aprofundando mais nos genéricos e essa resposta me ajudou muito na organização, muitas informações precisas em resumo, obrigado!
Testo Testini
27
Uma variável de tipo, <T>, pode ser qualquer tipo não primitivo que você especificar: qualquer tipo de classe, qualquer tipo de interface, qualquer tipo de matriz ou mesmo outra variável de tipo.
Os nomes dos parâmetros de tipo mais usados são:
Elemento E (usado extensivamente pelo Java Collections Framework)
Respostas:
Bem, não há diferença entre os dois primeiros - eles estão apenas usando nomes diferentes para o parâmetro type (
E
ouT
).A terceira não é uma declaração válida -
?
é usada como curinga que é usada ao fornecer um argumento de tipo , por exemplo,List<?> foo = ...
significa quefoo
se refere a uma lista de algum tipo, mas não sabemos o que.Tudo isso é genérico , que é um tópico bastante grande. Você pode aprender sobre isso através dos seguintes recursos, embora haja mais disponíveis, é claro:
fonte
T
eE
- eles são apenas identificadores. Você poderia escreverKeyValuePair<K, V>
por exemplo.?
tem um significado especial.É mais convenção do que qualquer outra coisa.
T
deve ser um tipoE
deve ser um elemento (List<E>
: uma lista de elementos)K
é a chave (em aMap<K,V>
)V
é Value (como valor de retorno ou valor mapeado)Eles são totalmente intercambiáveis (não obstante os conflitos na mesma declaração).
fonte
As respostas anteriores explicam os parâmetros de tipo (T, E etc.), mas não explicam o caractere curinga "?" Ou as diferenças entre eles; portanto, abordarei isso.
Primeiro, só para esclarecer: os parâmetros curinga e tipo não são os mesmos. Onde os parâmetros de tipo definem um tipo de variável (por exemplo, T) que representa o tipo de um escopo, o curinga não: o curinga apenas define um conjunto de tipos permitidos que você pode usar para um tipo genérico. Sem qualquer delimitação (
extends
ousuper
), o curinga significa "use qualquer tipo aqui".O curinga sempre se encontra entre colchetes angulares e só tem significado no contexto de um tipo genérico:
Nunca
ou
Fica mais confuso onde eles se sobrepõem. Por exemplo:
Há muita sobreposição no que é possível com as definições de método. A seguir, são funcionalmente idênticos:
Então, se houver sobreposição, por que usar um ou outro? Às vezes, é honestamente apenas estilo: algumas pessoas dizem que se você não precisar de um parâmetro de tipo, você deve usar um curinga apenas para tornar o código mais simples / mais legível. Uma diferença principal que expliquei acima: parâmetros de tipo definem uma variável de tipo (por exemplo, T) que você pode usar em outro lugar no escopo; o curinga não. Caso contrário, existem duas grandes diferenças entre os parâmetros de tipo e o curinga:
Parâmetros de tipo podem ter várias classes delimitadoras; o curinga não pode:
O curinga pode ter limites mais baixos; params de tipo não podem:
No exemplo acima,
List<? super Integer>
defineInteger
como um limite inferior no curinga, o que significa que o tipo de Lista deve ser Inteiro ou um supertipo de Inteiro. O limite de tipo genérico está além do que quero abordar em detalhes. Em resumo, permite definir quais tipos podem ser de um tipo genérico. Isso torna possível o tratamento de genéricos polimorficamente. Por exemplo, com:Você pode passar um
List<Integer>
,List<Float>
,List<Byte>
, etc paranumbers
. Sem delimitação de tipos, isso não funcionará - é assim que os genéricos são.Finalmente, aqui está uma definição de método que usa o curinga para fazer algo que eu acho que você não pode fazer de outra maneira:
numberSuper
pode ser uma lista de números ou qualquer supertipo de número (por exemplo,List<Object>
) eelem
deve ser um número ou qualquer subtipo. Com todas as delimitações, o compilador pode ter certeza de que.add()
é tipicamente seguro .fonte
Uma variável de tipo, <T>, pode ser qualquer tipo não primitivo que você especificar: qualquer tipo de classe, qualquer tipo de interface, qualquer tipo de matriz ou mesmo outra variável de tipo.
Os nomes dos parâmetros de tipo mais usados são:
No Java 7, é permitido instanciar assim:
fonte
Os nomes dos parâmetros de tipo mais usados são:
Você verá esses nomes usados em toda a API do Java SE
fonte
O compilador fará uma captura para cada curinga (por exemplo, ponto de interrogação na Lista) quando compuser uma função como:
No entanto, um tipo genérico como V ficaria bem e o tornaria um método genérico :
fonte