Dudo que haya alguna diferencia. Supongo que es solo un nombre para ese tipo de parámetro. ¿Y el último es válido?
CodesInChaos
Respuestas:
231
Bueno, no hay diferencia entre los dos primeros: solo usan nombres diferentes para el parámetro de tipo ( Eo T).
La tercera no es una declaración válida: ?se usa como comodín que se usa cuando se proporciona un argumento de tipo , por ejemplo, List<?> foo = ...significa que se foorefiere a una lista de algún tipo, pero no sabemos qué.
Todo esto es genérico , que es un tema bastante importante. Es posible que desee conocerlo a través de los siguientes recursos, aunque, por supuesto, hay más disponibles:
Parece que el enlace al PDF está roto. He encontrado lo que parece ser una copia aquí , pero no puedo estar 100% seguro ya que no sé cómo era el original.
John
2
@ John: Sí, ese es el. Editará un enlace, ya sea uno u Oracle ...
Jon Skeet
¿Hay algo más que T, E y? utilizado en genéricos? Si es así, ¿qué son y qué significan?
sofs1
1
@ sofs1: No tiene nada de especial Ty Eson solo identificadores. Podrías escribir KeyValuePair<K, V>por ejemplo. ?Sin embargo, tiene un significado especial.
Jon Skeet
215
Es más convención que cualquier otra cosa.
T está destinado a ser un tipo
Eestá destinado a ser un Elemento ( List<E>: una lista de Elementos)
Kes clave (en a Map<K,V>)
V es Valor (como valor de retorno o valor asignado)
Son totalmente intercambiables (a pesar de los conflictos en la misma declaración).
La letra entre <> es solo un nombre. Lo que describe en su respuesta son solo convenciones. Ni siquiera tiene que ser una letra mayúscula; puede usar cualquier nombre que desee, al igual que puede dar clases, variables, etc., cualquier nombre que desee.
No le explicaste al signo de interrogación. Voto negativo
Shinzou
129
Las respuestas anteriores explican los parámetros de tipo (T, E, etc.), pero no explican el comodín, "?", O las diferencias entre ellos, así que abordaré eso.
Primero, para ser claros: los parámetros comodín y tipo no son lo mismo. Cuando los parámetros de tipo definen un tipo de variable (por ejemplo, T) que representa el tipo para un ámbito, el comodín no: el comodín simplemente define un conjunto de tipos permitidos que puede usar para un tipo genérico. Sin ningún límite ( extendso super), el comodín significa "usar cualquier tipo aquí".
El comodín siempre viene entre paréntesis angulares, y solo tiene significado en el contexto de un tipo genérico:
publicvoid foo(List<?> listOfAnyType){...}// pass a List of any type
Nunca
public<?>? bar(? someType){...}// error. Must use type params here
Se vuelve más confuso donde se superponen. Por ejemplo:
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.
Hay mucha superposición en lo que es posible con las definiciones de métodos. Los siguientes son, funcionalmente, idénticos:
Entonces, si hay superposición, ¿por qué usar uno u otro? A veces, honestamente es solo estilo: algunas personas dicen que si no necesita un parámetro de tipo, debe usar un comodín solo para hacer que el código sea más simple / legible. Una diferencia principal que expliqué anteriormente: los parámetros de tipo definen una variable de tipo (por ejemplo, T) que puede usar en cualquier otra parte del alcance; el comodín no. De lo contrario, hay dos grandes diferencias entre los parámetros de tipo y el comodín:
Los params de tipo pueden tener múltiples clases limitantes; el comodín no puede:
El comodín puede tener límites inferiores; los params tipo no pueden:
publicvoid bar(List<?superInteger> list){...}
En lo anterior, se List<? super Integer>define Integercomo un límite inferior en el comodín, lo que significa que el tipo de Lista debe ser Entero o un supertipo de Entero. El límite de tipo genérico está más allá de lo que quiero cubrir en detalle. En resumen, le permite definir qué tipos puede ser un tipo genérico. Esto hace posible el tratamiento de genéricos polimórficos. Por ejemplo con:
publicvoid foo(List<?extendsNumber> numbers){...}
Puede pasar un List<Integer>, List<Float>, List<Byte>, etc., para numbers. Sin delimitación de tipos, esto no funcionará, así son los genéricos.
Finalmente, aquí hay una definición de método que usa el comodín para hacer algo que no creo que pueda hacer de otra manera:
numberSuperpuede ser una Lista de números o cualquier supertipo de Número (por ejemplo, List<Object>), y elemdebe ser Número o cualquier subtipo. Con todos los límites, el compilador puede estar seguro de que .add()es seguro.
No. El objetivo de ese ejemplo es mostrar una firma que admite polimórficamente una Lista de números y los subtipos de Número. Para esto, usas "extiende". Es decir, "pásame una lista de números o cualquier cosa que extienda el número" (List <Integer>, List <Float>, lo que sea). Un método como este podría iterar a través de la lista y, para cada elemento, "e", ejecutar, por ejemplo, e.floatValue (). No importa qué subtipo (extensión) de Número pase; siempre podrá ".floatValue ()", porque .floatValue () es un método de Número.
Hawkeye Parker
En su último ejemplo, "List <? Super Number>" podría ser simplemente "List <Number>" ya que el método no permite nada más genérico.
jessarah
@jessarah no. Tal vez mi ejemplo no está claro, pero menciono en el ejemplo que adder () podría tomar una Lista <Objeto> (El objeto es una superclase de Número). Si desea que pueda hacer esto, debe tener la firma "Lista <? Super número>". Ese es exactamente el punto de "super" aquí.
Hawkeye Parker
2
Esta respuesta es muy buena para explicar las diferencias entre los comodines y los parámetros de tipo, debería haber una pregunta específica con esta respuesta. Estoy profundizando en los genéricos últimamente y esta respuesta me ayudó mucho a armar las cosas, muchas informaciones precisas en resumen, ¡gracias!
Testo Testini
27
Una variable de tipo, <T>, puede ser cualquier tipo no primitivo que especifique: cualquier tipo de clase, cualquier tipo de interfaz, cualquier tipo de matriz o incluso otra variable de tipo.
Los nombres de parámetros de tipo más utilizados son:
E - Elemento (usado ampliamente por el Java Collections Framework)
K - Clave
N - Número
T - Tipo
V - Valor
En Java 7 se permite crear instancias de esta manera:
Respuestas:
Bueno, no hay diferencia entre los dos primeros: solo usan nombres diferentes para el parámetro de tipo (
EoT).La tercera no es una declaración válida:
?se usa como comodín que se usa cuando se proporciona un argumento de tipo , por ejemplo,List<?> foo = ...significa que sefoorefiere a una lista de algún tipo, pero no sabemos qué.Todo esto es genérico , que es un tema bastante importante. Es posible que desee conocerlo a través de los siguientes recursos, aunque, por supuesto, hay más disponibles:
fuente
TyEson solo identificadores. Podrías escribirKeyValuePair<K, V>por ejemplo.?Sin embargo, tiene un significado especial.Es más convención que cualquier otra cosa.
Testá destinado a ser un tipoEestá destinado a ser un Elemento (List<E>: una lista de Elementos)Kes clave (en aMap<K,V>)Ves Valor (como valor de retorno o valor asignado)Son totalmente intercambiables (a pesar de los conflictos en la misma declaración).
fuente
Las respuestas anteriores explican los parámetros de tipo (T, E, etc.), pero no explican el comodín, "?", O las diferencias entre ellos, así que abordaré eso.
Primero, para ser claros: los parámetros comodín y tipo no son lo mismo. Cuando los parámetros de tipo definen un tipo de variable (por ejemplo, T) que representa el tipo para un ámbito, el comodín no: el comodín simplemente define un conjunto de tipos permitidos que puede usar para un tipo genérico. Sin ningún límite (
extendsosuper), el comodín significa "usar cualquier tipo aquí".El comodín siempre viene entre paréntesis angulares, y solo tiene significado en el contexto de un tipo genérico:
Nunca
o
Se vuelve más confuso donde se superponen. Por ejemplo:
Hay mucha superposición en lo que es posible con las definiciones de métodos. Los siguientes son, funcionalmente, idénticos:
Entonces, si hay superposición, ¿por qué usar uno u otro? A veces, honestamente es solo estilo: algunas personas dicen que si no necesita un parámetro de tipo, debe usar un comodín solo para hacer que el código sea más simple / legible. Una diferencia principal que expliqué anteriormente: los parámetros de tipo definen una variable de tipo (por ejemplo, T) que puede usar en cualquier otra parte del alcance; el comodín no. De lo contrario, hay dos grandes diferencias entre los parámetros de tipo y el comodín:
Los params de tipo pueden tener múltiples clases limitantes; el comodín no puede:
El comodín puede tener límites inferiores; los params tipo no pueden:
En lo anterior, se
List<? super Integer>defineIntegercomo un límite inferior en el comodín, lo que significa que el tipo de Lista debe ser Entero o un supertipo de Entero. El límite de tipo genérico está más allá de lo que quiero cubrir en detalle. En resumen, le permite definir qué tipos puede ser un tipo genérico. Esto hace posible el tratamiento de genéricos polimórficos. Por ejemplo con:Puede pasar un
List<Integer>,List<Float>,List<Byte>, etc., paranumbers. Sin delimitación de tipos, esto no funcionará, así son los genéricos.Finalmente, aquí hay una definición de método que usa el comodín para hacer algo que no creo que pueda hacer de otra manera:
numberSuperpuede ser una Lista de números o cualquier supertipo de Número (por ejemplo,List<Object>), yelemdebe ser Número o cualquier subtipo. Con todos los límites, el compilador puede estar seguro de que.add()es seguro.fuente
Una variable de tipo, <T>, puede ser cualquier tipo no primitivo que especifique: cualquier tipo de clase, cualquier tipo de interfaz, cualquier tipo de matriz o incluso otra variable de tipo.
Los nombres de parámetros de tipo más utilizados son:
En Java 7 se permite crear instancias de esta manera:
fuente
Los nombres de parámetros de tipo más utilizados son:
Verá estos nombres utilizados en la API Java SE
fuente
el compilador realizará una captura para cada comodín (p. ej., signo de interrogación en la Lista) cuando cree una función como:
Sin embargo, un tipo genérico como V estaría bien y lo convertiría en un método genérico :
fuente