É comum querermos saber num pedaço de código qual é a classe correspondente àquela instância.
Isto é perfeitamente simples quando temos uma instancia:
this.getClass();
O problema aparece quando queremos saber qual é a classe num contexto estático. Pode até parecer estranho que se venha a necessitar de fazer isto, mas garanto que já precisei disto várias vezes.
Portanto, se não temos uma instância, como obtemos a Class? Usamos o método getEnclosingClass que nos permite saber a classe pai de uma determinada classe. Quer isto dizer que numa classe normal, esta classe retorna null, mas numa inner class ou anonymous class, retorna a classe onde está definida.
Como tal, criamos uma anonymous class da forma mais simples que se possa:
new Object(){}.getEnclosingClass();
Repare-se que não é só instanciar o objecto, temos de lhe dar uma implementação default para ficar definido como uma anonymous class e assim nos dar a classe certa.
No entanto, este método tem uma limitação importante. Suponhamos que temos as seguintes classes:
public class A {
public String getMyName() {
return this.getClass().getName();
}
}
public class B extends A {
}
Se eu invocar o método getMyName() sobre uma instância de A e sobre uma instância de B, tenho os seguintes resultados:
new A().getMyName() -> "A" new B().getMyName() -> "B"
Tudo normal e lógico, temos o nome da classe que foi instanciada.
Agora suponhamos que o método getMyName é static e usamos aquele truque referido ali em cima e passamos a definir a classe A da seguinte forma:
public class A {
public static String getMyName() {
return new Object(){}.getEnclosingClass().getName();
}
}
Ao testarmos invocar o método em A e B, obtemos:
A.getMyName() -> "A" B.getMyName() -> "A"
Ou seja, sabemos a classe onde o método foi definido e não a classe que está a ser invocada. Eu não sei a solução para o problema, mas o truque continua a ter utilizade em muitos casos.

4 respostas até ao momento ↓
PJG // Ago 25, 2008 at 21:23
public class GetMyClassTrial {
public static void main(String[] args) {
System.out.println(”I know my class : ” + GetMyClassTrial.class.getName());
System.out.println(”I don’t know my class : ” + Thread.currentThread().getStackTrace()[2].getClassName());
}
}
Ruben Badaró // Ago 25, 2008 at 21:56
Tinha-me enganado no segundo output, ambas as respostas davam A.
Penso que a tua solução também me dá a superclasse e nunca a subclasse. E o que eu queria era saber qual a classe que foi utilizada para invocar o método (no meu exemplo, que me desse B e não A)
PJG // Ago 25, 2008 at 22:20
Não tinha percebido bem.
Mas a verdade é que apenas te será possível encontrar qual a classe em que o método foi DECLARADO.
A menos que estejas num ambiente muito permissivo, com o código compilado com informação de debug (para ter etiquetas de número de linha no bytecode) , e utilizes a informação na stack trace para analisar o código que invocou o método, já que as duas chamadas que apresentas são representadas por bytecode diferente. Algo do tipo:
INVOKESTATIC org/zonaj/whatever/package/A$getMyName()V
INVOKESTATIC org/zonaj/whatever/package/B$getMyName()V
=:o)
Have Fun!
PJG // Ago 25, 2008 at 22:22
Onde escrevi:
“o código que invocou o método”
…queria escrever:
“o bytecode que invocou o método”
Sorry!
Deixe um comentário