Inheritance: is there a way to open the class from which the method was called?

With this code:

class SuperTest { SuperTest() { whoAmI(); } void whoAmI() { System.out.println(getClass().getName()); } } class Test extends SuperTest { Test() { whoAmI(); } } 

new Test() print "Test" twice. As a newbie, I expected the output to be "SuperTest / Test" . Now I understand why this is not possible, and why the implicit this will only refer to the child type.

However, I cannot find what should be whoAmI() for the actual output of the SuperTest / Test output. It is said differently: how can whoAmI() access the name of the type from which it is called?

EDIT: I am changing the name of the question to a new one that better describes the problem. (old was: Inheritance: does "this equivalent" construct exist for referencing a super-type from a derived type).

+7
java inheritance this
source share
3 answers

This is the expected behavior, because in both cases getType() is called on the same object of type Test . This is because the JVM knows what type of object to create has the Test derived class when the base constructor is called, so this is a print type.

This behavior is not universal for all programming languages, but it works just like that in Java.

If a class wants to access its own Class object, it can do it statically, i.e. using the expression SuperTest.class .

To get the desired behavior, you can pass the class to whoAmI from the constructor, for example:

 class SuperTest { SuperTest() { whoAmI(SuperTest.class); } void whoAmI(Class c) { System.out.println(c.getName()); } } class Test extends SuperTest { Test() { whoAmI(Test.class); } } 
+5
source share

For your pleasure, here is a test program demonstrating "whoAmI" that will print at any required pedigree depth:

 public class Test { public static void main(String[] args) { Sub2 sub2 = new Sub2(); System.out.println("Four levels"); sub2.whoAmi(4); System.out.println("Two levels"); sub2.whoAmi(2); } public void whoAmi(int levels){ if(levels > 1){ Class<? extends Object> ancestor = getClass(); for(int i=1; i<levels && ancestor != null; i++){ ancestor = ancestor.getSuperclass(); } if(ancestor != null){ System.out.println(ancestor.getName()); } whoAmi(levels - 1); } else { System.out.println(getClass().getName()); } } } class Sub1 extends Test { } class Sub2 extends Sub1 { } 
0
source share

how whoAmI() access the name of the type from which it is called?

You can access the superclass using Class.getSuperclass() :

 void whoAmI() { Class superclass = getClass().getSuperclass(); String superclassText = "no superclass found"; if (superclass != null) superclassText = superclass.getName(); System.out.println(superclassText); } 

This technically answers your question, but only because I suggested that the method we are discussing belongs to the superclass (which it does in your example).

But perhaps you really want to know the answer to "How can a method determine which class is defined, even if it is called on an instance of a subclass?" That would be a much more complicated question. While java.lang.reflect.Method.getDeclaringClass() seems to do what you ask, you first need to declare an instance of the Class class (i.e. SuperTest.class ) that wins the item - if you had was that you would not need to use java.lang.reflect.Method at all.

However, if I can change the premise a bit, suppose you insert each class with a static instance of the class as follows:

 private final static Class THIS_CLASS = SuperTest.class; 

Then it becomes possible to write a method that does not access the declaring class by name, since it can assume that whatever class it gets in brackets will have THIS_CLASS :

 void whoAmI() { final String myName = "whoAmI"; final Class[] myParamTypes = {}; String result; try { Method thisMethod = THIS_CLASS.getDeclaredMethod(myName, myParamTypes); result = "I am " + thisMethod.getDeclaringClass().getName() + "." + myName + Arrays.toString(myParamTypes); // Now swap the square brackets from Arrays.toString for parentheses result = result.replaceAll("\\[", "\\(").replaceAll("\\]", "\\)"); } catch (NoSuchMethodException | SecurityException ex) { result = ex.toString(); } System.out.println(result); } 

This will exit I am packagename.MinsSuperTest.whoAmI() .

0
source share

All Articles