Clase genérica de Java: determinar el tipo

Si estoy creando una clase java para que sea genérica, como por ejemplo:

public class Foo 

¿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.

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]; } 

A diferencia de .NET, los generics de Java se implementan mediante una técnica llamada “borrado de tipo”.

Lo que esto significa es que el comstackdor 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 comstackdas con javap o herramientas similares, encontrará que una List es una List simple (de Object ) en el archivo de clase, tal como estaba en el código pre-Java-5.

El comstackdor “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 comstackdor termina con ellos:

Java 5:

 List stringList = new ArrayList(); 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 comstackdor 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 recomstackr 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 comstackdor 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.

Debido a la borradura de tipo , no hay forma de hacer esto directamente. Sin embargo, lo que podrías hacer es pasar una Class 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 enumeración .

El problema es que la mayoría de las cosas genéricas desaparecerán durante la comstackció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

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 public ???? Bar() { //else condition goes here } 

Y entonces

 public class DateFoo extends Foo public ???? Bar() { //Whatever you would have put in if(T == Date) would go here. } 

El objective de una clase genérica es que no necesita saber el tipo que se está utilizando …

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 objective real y concreto.

Estoy de acuerdo con Visage. Generics es para validación en tiempo de comstackción, no para tipeo dynamic 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.