java - objeto - Extendiendo Clases Genéricas
list generica java (3)
public class MyGeneric<T, E> {}
public class Extend1<T, E> extends MyGeneric<T, E> {}
public class Extend2 extends MyGeneric<String, Object> {}
Hasta donde yo sé, ambas subclases en el ejemplo anterior son válidas. Me preguntaba cómo sabe Java cuándo se van a definir los tipos dados en la superclase cuando se crea una instancia de la subclase, y cuando son nombres de clase reales (es decir, ¿cómo sabe que T, E no son nombres de clase)?
Una nota al margen, ¿es permisible (incluso si no es común) usar más de una letra para los tipos genéricos? ¿Qué pasa si (a través de algún error de error de planificación) Los tipos entran en conflicto con una clase existente, por ejemplo,
public class E{}
public class Foo<E>{}
¿Qué pasa entonces?
Editar: Gracias por responder tan rápido. Para responder mi primera pregunta, la respuesta de Joachim es más efectiva.
Para responder al punto, la respuesta de aioobe es más clara
Me preguntaba cómo sabe Java cuándo se van a definir los tipos dados en la superclase cuando se instaura la subclase, y cuándo son nombres de clase reales (es decir, ¿cómo sabe que T, E no son nombres de clase)?
A Java no le importa Si lo haces...
class MyGeneric<String> extends ArrayList<String> {
String value;
}
¿Está permitido (incluso si no es común) usar más de una letra para los tipos genéricos? ¿Qué pasa si (a través de algún error de error de planificación) Los tipos entran en conflicto con una clase existente, por ejemplo,
Sí, puede usar cualquier identificador Java válido para los parámetros de tipo.
Los nombres pueden estar en conflicto, pero Java no tratará esto como un error. Los identificadores entre <
... >
siempre se tratarán como parámetros de tipo, independientemente de si el identificador corresponde a un nombre de clase.
Aunque puede ser bastante confuso. Aquí hay un ejemplo:
class MyGeneric<String> extends java.util.ArrayList<String> {
String value;
}
class Test {
public static void main(String... args) throws Exception {
MyGeneric<Integer> obj = new MyGeneric<Integer>();
obj.value = 5;
// ^
// |
// ''--- Assign an integer to what seems to be a String!
}
}
Pregunta similar:
No hay problema con:
public class E{}
public class Foo<E>{}
Porque en el contexto de Foo<E>
, E
es un tipo.
Veamos esta definición:
public class Extend1<T, E> extends MyGeneric<T, E> {}
Aquí T
y E
están presentes dos veces y en dos roles diferentes
- en
Extend1<T,E>
define los argumentos de tipo. Esto significa que el tipoExtend1
tiene dos argumentos de tipo (sin límites)T
yE
Esto le dice al compilador de Java que aquellos que usanExtend1
necesitan especificar los tipos. - en
extends MyGeneric<T,E>
usa los argumentos de tipo definidos previamente. Si no se conociera queT
yE
son argumentos de tipo aquí, entoncesT
yE
serían referencias de tipo simple, es decir, el compilador buscaría clases (o interfaces, ...) llamadasT
yE
(y probablemente no las encuentre) .
Sí, los argumentos de tipo siguen las mismas reglas sintácticas que cualquier otro identificador en Java, por lo que puedes usar letras múltiples ABC
o incluso nombres que pueden ser confusos (usar un argumento tipo llamado String
es legal, pero muy confuso).
Los nombres de argumento de tipo de letra única son simplemente una estrategia de denominación muy común.