En contraste con .NET, los genéricos de Java se implementan mediante una técnica llamada "borrado de tipos".
Lo que esto significa es que el compilador utilizará la información de tipo cuando se generan los archivos de clase, pero no transferir esta información al código de bytes. Si nos fijamos en las clases compiladas con javap o herramientas similares, se dará cuenta de que un List<String>
es un simple List
(de Object
) en el archivo de clase, al igual que lo fue en pre-Java-5 código.
Código acceder a la lista genérica será "reescrito" por el compilador para incluir los elencos que tendría que escribir a sí mismo en las versiones anteriores. En efecto, los dos fragmentos de código son idénticos desde el punto de vista de código de bytes, una vez que el compilador se hace 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 los valores de una clase genérica en Java 5 se insertan automáticamente para el 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 interoperables las bibliotecas antiguas y el nuevo código genérico sin necesidad de volver a compilar 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 ha 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.
El deseo de hacer esto es casi seguro que sea una mala elección de diseño. Lo más probable es que la declaración if requiera el conocimiento de cada "tipo" para poder implementarse, por lo que probablemente debería tener todas esas clases del mismo tipo padre, y "do this" debería ser un método virtual. Puede implicar envolver clases, pero en general su diseño mejorará si continúa por este camino. –
Las posibilidades en los enunciados if son casos extremos entre todos los posibles tipos de llamadas, que requieren implementaciones completamente separadas. Estoy de acuerdo con lo que estás diciendo aquí, pero la aplicación específica es una piedra y un lugar difícil. –
La necesidad de obtener la clase para un param tipo genérico no siempre es una mala decisión de diseño. Un requisito legítimo (¡mío! :) podría ser una llamada a un método que requiera un parámetro Class <>. – dahvyd