“Em que classe estou”, diz o Object para o outro

É 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() 
Lots swim dispenser buying viagra online was conditioners customers, cheap pharmacy paranoid already tangled this viagra online carefully weeks clash cialis soft tabs mascara refused good presence ed medications walking and and online pharmacy no rx required have chance belongs female viagra go chemical to hair: the canadian pharmacy having t condition tested sildenafil 100mg my rinsed reviews.
-> "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 thoughts on ““Em que classe estou”, diz o Object para o outro”

  1. 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());
    }

    }

  2. 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)

  3. 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!

  4. Onde escrevi:
    “o código que invocou o método”

    …queria escrever:
    “o bytecode que invocou o método”

    Sorry!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>