objeto - tipos genéricos java
Clase genérica de Java: determinar el tipo (8)
A diferencia de .NET, los genéricos de Java se implementan mediante una técnica llamada "borrado de tipo".
Lo que esto significa es que el compilador usará la información de tipo al generar los archivos de clase, pero no transferirá esta información al código de bytes. Si observa las clases compiladas con javap o herramientas similares, encontrará que una List<String>
es una List
simple (de Object
) en el archivo de clase, tal como estaba en el código pre-Java-5.
El compilador "reescribirá" el código que accede a la Lista genérica para incluir los moldes que debería escribir usted mismo en versiones anteriores. En efecto, los siguientes dos fragmentos de código son idénticos desde una perspectiva de código de bytes una vez que el compilador termina con ellos:
Java 5:
List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
String hw = stringList.get(0);
Java 1.4 y antes:
List stringList = new ArrayList();
stringList.add("Hello World");
String hw = (String)stringList.get(0);
Al leer valores de una clase genérica en Java 5, se inserta automáticamente la conversión necesaria al parámetro de tipo declarado. Al insertar, el compilador verificará el valor que intenta colocar y abortará con un error si no es un String.
Todo se hizo para mantener las bibliotecas antiguas y el nuevo código genérico interoperable sin necesidad de recompilar las librerías existentes. Esta es una gran ventaja sobre el modo .NET donde las clases genéricas y las no genéricas conviven una al lado de la otra, pero no se pueden intercambiar libremente.
Ambos enfoques tienen sus pros y sus contras, pero así es en Java.
Para volver a su pregunta original: No podrá obtener la información de tipo en tiempo de ejecución, porque simplemente ya no está allí, una vez que el compilador haya hecho su trabajo. Esto seguramente es una limitación en algunos aspectos y existen algunas formas de mal humor que generalmente se basan en almacenar una instancia de clase en algún lugar, pero esta no es una función estándar.
Si estoy creando una clase java para que sea genérica, como por ejemplo:
public class Foo<T>
¿Cómo puede uno determinar internamente a esa clase, qué ''T'' terminó siendo?
public ???? Bar()
{
//if its type 1
// do this
//if its type 2
// do this
//if its type 3
// do this
//if its type 4
// do this
}
Busqué en la API de Java y jugué con las cosas de Reflection, instanceof, getClass, .class, etc., pero parece que no puedo encontrar cara o cruz de ellas. Siento que estoy cerca y solo necesito combinar varias llamadas, pero sigo quedándome corto.
Para ser más específico, estoy tratando de determinar si la clase fue instanciada con uno de los 3 tipos posibles.
Debido a la borradura de tipo , no hay forma de hacer esto directamente. Sin embargo, lo que podrías hacer es pasar una Class<T>
al constructor y retenerla dentro de tu clase. Luego puede verificarlo contra los tres posibles tipos de Class
que permite.
Sin embargo, si solo hay tres tipos posibles, es posible que desee considerar la refactorización en una enum .
El objetivo de una clase genérica es que no necesita saber el tipo que se está utilizando ...
El problema es que la mayoría de las cosas genéricas desaparecerán durante la compilación.
Una solución común es guardar el tipo durante la creación del Objeto.
Para una breve introducción en el comportamiento de borrado de tipo de Java, lea esta página
Estoy de acuerdo con Visage. Generics es para validación en tiempo de compilación, no para tipeo dinámico en tiempo de ejecución. Parece que lo que necesitas es realmente solo el patrón de fábrica. Pero si tu "haz esto" no es creación de instancias, entonces un Enum simple también funcionará igual de bien. Al igual que Michael dijo, si tienes un ejemplo un poco más concreto, obtendrás mejores respuestas.
He usado una solución similar a lo que explica aquí para algunos proyectos y me pareció bastante útil.
http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/
La cuestión es usar lo siguiente:
public Class returnedClass() {
ParameterizedType parameterizedType = (ParameterizedType)getClass()
.getGenericSuperclass();
return (Class) parameterizedType.getActualTypeArguments()[0];
}
Parece que lo que desea, de hecho, no es una clase genérica, sino una interfaz con varias implementaciones diferentes. Pero tal vez sería más claro si estableciera su objetivo real y concreto.
Si conoce algunos tipos específicos que son significativos, debe crear subclases de su tipo genérico con la implementación.
Asi que
public class Foo<T>
public ???? Bar()
{
//else condition goes here
}
Y entonces
public class DateFoo extends Foo<Date>
public ???? Bar()
{
//Whatever you would have put in if(T == Date) would go here.
}