Genéricos Java:Comparando a classe do Object o com <E>
Pergunta
Digamos que eu tenha a seguinte classe:
public class Test<E> {
public boolean sameClassAs(Object o) {
// TODO help!
}
}
Como eu verificaria isso o
é a mesma classe que E
?
Test<String> test = new Test<String>();
test.sameClassAs("a string"); // returns true;
test.sameClassAs(4); // returns false;
Não consigo alterar a assinatura do método de (Object o)
já que estou substituindo uma superclasse e não consigo escolher a assinatura do meu método.
Eu também preferiria não tentar uma conversão e, em seguida, capturar a exceção resultante se ela falhar.
Solução
Uma instância de Test
não tem informações sobre o que E
está em tempo de execução.Então, você precisa passar por um Class<E>
para o construtor 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;
}
}
Se você quiser um relacionamento "instanceof", use Class.isAssignableFrom
ao invés de Class
comparação.Observação, E
precisará ser um tipo não genérico, pelo mesmo motivo Test
precisa do Class
objeto.
Para obter exemplos na API Java, consulte java.util.Collections.checkedSet
e semelhantes.
Outras dicas
O método que sempre usei está abaixo.É uma dor e um pouco feio, mas não encontrei um melhor.Você tem que passar o tipo de classe na construção, pois quando os genéricos são compilados, as informações da classe são perdidas.
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);
}
}
Eu só poderia fazer funcionar assim:
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);
}
}
Eu estava apenas tentando fazer a mesma coisa, e um truque interessante que acabei de perceber é que você pode tentar uma conversão e, se a conversão falhar, ClassCastException será lançada.Você pode pegar isso e fazer o que for.
então seu método sameClassAs deve ser parecido com:
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;
}
}