How do I get the class name in a static context?

Asked

Viewed 2,257 times

3

i want to get the name of the class that called my method

class A {
    public static String getClass(){
       return getCalledClass(); /*Supondo que exista esse metodo*/
    }
}

class B extends A{

}

When I do:


System.out.println(A.getClass()); // deve mostrar "A"
System.out.println(B.getClass()); // deve mostrar "B"

  • 1

    As far as I know, this is not possible. Both static and instance methods are inherited by subclasses, but your behavior is somewhat different. In my mind, though JVM invokes methods differently in bytecode (P.S. I used getClass2 not to give error), since the same is dispatched (dispatched) I believe that the information about the original call is lost. But I may be wrong, it is good to wait for the answer from someone who understands the subject better.

2 answers

3

I do not believe it is possible to get the name of the base class via reflection when this class is static. You will need to have a direct reference to the class you want to know the name of. This is because in java, when the signatures of the base and drift methods collide, the derivative does not override the method, something called Hide (see an example here).

According to the object-oriented paradigm, it is necessary to have an instance for the overload to occur. In this case, we have static methods, that belong to the class and not to an instance. These methods are solved at compile time and not dynamically (at runtime), as with instance methods. So the polymorphism that we’re used to doesn’t exist in the static context.

Taking into account your example, if we do:

class A {
    public static String getNome(){
        return A.class.getSimpleName();
    }
}

class B extends A {
}

System.out.println(A.getNome()); // vai mostra "A"
System.out.println(B.getNome()); // vai mostrar "A"

A change in this example to come close to what we want:

class A {
    public static String getNome(){
        return A.class.getSimpleName();
    }
}

class B extends A {
    public static String getNome(){
        return B.class.getSimpleName();
    }
}

System.out.println(A.getNome()); // vai mostra "A"
System.out.println(B.getNome()); // vai mostrar "B"

So far so good, is the expected behavior. However, when you do not use a direct reference to the B, the problem happens again.

// mas o problema persiste quando não se utiliza um referência direta para o `B`
A x = new B();
System.out.println(x.getNome()); // vai mostrar "A"

What if we tried to analyze the stack trace

When analyzed the stack trace of the calls, there is no call to class B, when there is no direct reference and "overload" of the method getNome(), see:

class A {
    public static String getNome(){
        String out = "";

        for (StackTraceElement var : Thread.currentThread().getStackTrace()){
            out += var.getClassName() + "->";
        }

        out += ".";

       return out;
    }
}

class B extends A {
}

System.out.println(B.getNome());
// vai mostrar: java.lang.Thread->A->HelloWorld->.

Even with the reference to B, there is no record in the stack trace. The same goes for:

System.out.println(A.getNome());
// vai mostrar: java.lang.Thread->A->HelloWorld->.

and even "overloading" the method in B, the expected behaviour does not occur:

class B extends A {
    // Agora "sobrecarregando" o método getNome()
    public static String getNome(){
        return A.getNome();
    }
}

System.out.println(B.getNome());
// vai mostrar: java.lang.Thread->A->HelloWorld->.

To paraphrase mathematicians: soon, it is "demonstrated", that it is not possible to obtain the name of the class "caller" using polymorph and reflection without a direct reference to the class "caller".

In this case, having a direct reference to the "calling" class and implementing all this paraphernalia is absurd! If you have the reference of what you want to know the name use B.class.getSimpleName() or A.class.getSimpleName(). If you already have everything at compile time, you don’t need to solve at runtime (dynamically) :)

2

stack.Leading

package stack;

public class Principal {
    public static void main(String[] args) {
        //Dinâmico
        A a = new A();
        B b = new B();
        a.getClasse();
        b.getClasse();
        //Estático
        A.getStaticClasse();
        B.getStaticClasse();
    }
}

stack.To

public  class A {
       public void getClasse(){
               System.out.println("classe = " + this.getClass());
       }
       
       public static void getStaticClasse(){
               System.out.println("classe estatica = " + A.class.getName());
       }
}

stack.B

package stack;

public class B extends A{
    public static void getStaticClasse(){
           System.out.println("class estática= " + B.class.getName());
   }
}

Exit:

class = class stack.A
class = class stack.B
static class = stack.A
static class = stack.B

If you want to download the project, you can find it on Github

Note that you would have to create such a method in all classes, or the return would still be stack.A.

  • Although this is correct, it does not answer what was asked. (in your code the context is dynamic, not static)

  • 2

    @mgibsonbr, thank you for the warning. I have corrected the reply.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.