Genéricos de Java:Comparando la clase de Objeto o con <E>
Pregunta
Digamos que tengo la siguiente clase:
public class Test<E> {
public boolean sameClassAs(Object o) {
// TODO help!
}
}
¿Cómo comprobaría eso? o
es la misma clase que E
?
Test<String> test = new Test<String>();
test.sameClassAs("a string"); // returns true;
test.sameClassAs(4); // returns false;
No puedo cambiar la firma del método de (Object o)
ya que estoy anulando una superclase y no puedo elegir la firma de mi método.
También preferiría no seguir el camino de intentar una conversión y luego detectar la excepción resultante si falla.
Solución
Una instancia de Test
no tiene información de qué E
está en tiempo de ejecución.Entonces, necesitas pasar un Class<E>
al constructor de Test.
public class Test<E> {
private final Class<E> clazz;
public Test(Class<E> clazz) {
if (clazz == null) {
throw new NullPointerException();
}
this.clazz = clazz;
}
// To make things easier on clients:
public static <T> Test<T> create(Class<T> clazz) {
return new Test<T>(clazz);
}
public boolean sameClassAs(Object o) {
return o != null && o.getClass() == clazz;
}
}
Si desea una relación "instancia de", utilice Class.isAssignableFrom
en vez de Class
comparación.Nota, E
tendrá que ser de un tipo no genérico, por la misma razón Test
necesita el Class
objeto.
Para ver ejemplos en la API de Java, consulte java.util.Collections.checkedSet
y similares.
Otros consejos
El método que siempre he usado se encuentra a continuación.Es un fastidio y un poco feo, pero no he encontrado otro mejor.Debe pasar el tipo de clase durante la construcción, ya que cuando se compilan los genéricos, la información de la clase se pierde.
public class Test<E> {
private Class<E> clazz;
public Test(Class<E> clazz) {
this.clazz = clazz;
}
public boolean sameClassAs(Object o) {
return this.clazz.isInstance(o);
}
}
Sólo pude hacerlo funcionar así:
public class Test<E> {
private E e;
public void setE(E e) {
this.e = e;
}
public boolean sameClassAs(Object o) {
return (o.getClass().equals(e.getClass()));
}
public boolean sameClassAs2(Object o) {
return e.getClass().isInstance(o);
}
}
Estaba tratando de hacer lo mismo, y un buen truco que acabo de darme cuenta es que puedes probar una conversión y, si la conversión falla, se generará ClassCastException.Puedes captar eso y hacer lo que sea.
entonces tu método SameClassAs debería verse así:
public boolean sameClassAs(Object o) {
boolean same = false;
try {
E t = (E)o;
same = true;
} catch (ClassCastException e) {
// same is false, nothing else to do
} finally {
return same;
}
}