How to call a superclass method using Java reflection - java

I have two classes:
public class A {
public Object method() {...}
}
public class B extends A {
#Override
public Object method() {...}
}
I have an instance of B. How do I call A.method() from b? Basically, the same effect as calling super.method() from B.
B b = new B();
Class<?> superclass = b.getClass().getSuperclass();
Method method = superclass.getMethod("method", ArrayUtils.EMPTY_CLASS_ARRAY);
Object value = method.invoke(obj, ArrayUtils.EMPTY_OBJECT_ARRAY);
But the above code will still invoke B.method().

If you are using JDK7, you can use MethodHandle to achieve this:
public class Test extends Base {
public static void main(String[] args) throws Throwable {
MethodHandle h1 = MethodHandles.lookup().findSpecial(Base.class, "toString",
MethodType.methodType(String.class),
Test.class);
MethodHandle h2 = MethodHandles.lookup().findSpecial(Object.class, "toString",
MethodType.methodType(String.class),
Test.class);
System.out.println(h1.invoke(new Test())); // outputs Base
System.out.println(h2.invoke(new Test())); // outputs Base
}
#Override
public String toString() {
return "Test";
}
}
class Base {
#Override
public String toString() {
return "Base";
}
}

Building on #java4script’s answer, I noticed that you get an IllegalAccessException if you try to do this trick from outside the subclass (i.e., where you would normally be calling super.toString() to begin with). The in method allows you to bypass this only in some cases (such as when you are calling from the same package as Base and Sub). The only workaround I found for the general case is an extreme (and clearly nonportable) hack:
package p;
public class Base {
#Override public String toString() {
return "Base";
}
}
package p;
public class Sub extends Base {
#Override public String toString() {
return "Sub";
}
}
import p.Base;
import p.Sub;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
public class Demo {
public static void main(String[] args) throws Throwable {
System.out.println(new Sub());
Field IMPL_LOOKUP = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
IMPL_LOOKUP.setAccessible(true);
MethodHandles.Lookup lkp = (MethodHandles.Lookup) IMPL_LOOKUP.get(null);
MethodHandle h1 = lkp.findSpecial(Base.class, "toString", MethodType.methodType(String.class), Sub.class);
System.out.println(h1.invoke(new Sub()));
}
}
printing
Sub
Base

It's not possible. Method dispatching in java always considers the run-time type of the object, even when using reflection. See the javadoc for Method.invoke; in particular, this section:
If the underlying method is an
instance method, it is invoked using
dynamic method lookup as documented in
The Java Language Specification,
Second Edition, section 15.12.4.4; in
particular, overriding based on the
runtime type of the target object will
occur.

You can't, you'll need an instance of the super class because of the way methods dispatching works in Java.
You could try something like this:
import java.lang.reflect.*;
class A {
public void method() {
System.out.println("In a");
}
}
class B extends A {
#Override
public void method() {
System.out.println("In b");
}
}
class M {
public static void main( String ... args ) throws Exception {
A b = new B();
b.method();
b.getClass()
.getSuperclass()
.getMethod("method", new Class[]{} )
.invoke( b.getClass().getSuperclass().newInstance() ,new Object[]{} );
}
}
But most likely, it doesn't make sense, because you'll loose the data in b.

You can't do that. It would mean polymorphism is not working.
You need an instance of A. You can create one by superclass.newInstance() and then transfer all fields with something like BeanUtils.copyProperties(..) (from commons-beanutils). But that's a 'hack' - you should instead fix your design so that you don't need that.

I don't know how to do it in the case when You want to do the trick for included libraries, because the reflection doesn't work, but for my own code I would do this simple workaround:
public class A {
public Object method() {...}
}
public class B extends A {
#Override
public Object method() {...}
public Object methodSuper() {
return super.method();
}
}
For simple cases this is OK, for some automatic invocation not so much. For instance, when You have a chain
A1 super A2 super A3 ... super An
of inheriting classes, all overriding a method m. Then invoking m from A1 on an instance of An would require too much bad coding :-)

You can create a byte code sequence using a different this pointer before calling invokespecial.
Calling the super.toString() method of any object is like:
ALOAD X ;X = slot of object reference of the object to access
INVOKESPECIAL java/lang/Object.toString ()Ljava/lang/String;
POP
This way creating an anonymous class containing the necessary object is possible.

If you can't modify either class, you need to use reflection to use method handles. You need to use invokespecial calls to call super methods which can be done with MethodHandles. The MethodHandles.lookup() method creates a Lookup instance with the caller class and only permits special calls from that class. To call super methods from any class, get the constructor of Lookup:
var lookupConstructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class);
lookupConstructor.setAccessible(true);
Create an instance of it with class A or B passed as the parameter, and use unreflect with the reflected method object which already points to A internally (or use findSpecial):
var lookup = lookupConstructor.newInstance(B.class);
var method = A.class.getMethod("method");
var mHandle = lookup.unreflectSpecial(method, B.class);
// OR
var mHandle = lookup.findSpecial(A.class, "method", MethodType.methodType(returnType), B.class);
Note that the class specified in the constructor and the last argument of unreflectSpecial/findSpecial must be the same, although it doesn't matter which class it is as long as it's a subclass of A (or A itself).
The resulting MethodHandle ignores any overrides so it will always call the method belonging to the original Method object (A in this case) or the class specified as the first argument of findSpecial. When invoking the method, pass the B object as the first parameter, and any additional arguments:
Object ret = mHandle.invoke(b);

Related

Convert a Java Method object to a Function object [duplicate]

class A {
public static void foo() {}
}
class B {
public static void foo() {}
}
I have Class clazz = A.class; or B.class;
How do I access this via "clazz" assuming it might be assigned either 'A' or 'B'
It is only possible to access those methods using reflection. You cannot reference a class directly, only an instance of type Class.
To use reflection to invoke methodname(int a, String b):
Method m = clazz.getMethod("methodname", Integer.class, String.class);
m.invoke(null, 1, "Hello World!");
See Class.getMethod() and Method.invoke()
You may want to think about your design again, to avoid the need to dynamically call static methods.
You can invoke a static method via reflection like this :
Method method = clazz.getMethod("methodname", argstype);
Object o = method.invoke(null, args);
Where argstype is an array of arguments type and args is an array of parameters for the call. More informations on the following links :
getMethod()
invoke()
In your case, something like this should work :
Method method = clazz.getMethod("foo", null);
method.invoke(null, null); // foo returns nothing
You cannot access static methods without an explicit reference to the class.
No inheritance here, sorry, so you must either do:
A.foo()
or
B.foo()
If you really need it, you will have to do a check:
Object o = .... // eith an A or B instance.
if( o instanceof A ) {
A.foo()
} else {
B.foo()
}
But why don't you just make those functions instance functions, and let them implement an interface?
Okey, you have a class object. Then do:
Class c = ...;
c.getMethod("foo").invoke(null); // null to invoke static methods
According to my lack of knowledge the need for the requested construct is given by the fact that an interface doesn't offer the possibility of static abstract methods. Here is an example:
public enum Cheese implements Yumy {
GOUDA(49),
ESROM(40),
HWARTI(38);
private int percentage;
private Cheese(int fat100) {...} constructor
public void yamyam() {...} // as in Yumy
public static Cheese getByFat(int fat100) {...} // no chance to be part
of interface
};
I hope this isn't making too many assumptions or deviating too far from your question, but if your two classes share a common supertype and creating an instance is tolerable then you can:
Implement a common interface
Create an instance of the object via myClass.newInstance() (class must have an empty constructor)
Call the static method from the instance object.
interface Foo {
void foo();
}
class A implements Foo {...}
class B implements Foo {...}
<T extends Foo> public void something(Class<T> clazz) {
T myInstance = clazz.newInstance();
myInstance.foo();
}
...
something(A.class);
It's a little bizarre but in my case it proved to be useful, and I began by asking the very same question that you did.

How to force my subclass constructor not to call base class constructor?

public class Base {
public Base() {
foo();
}
public void foo() {
System.out.println("Base.foo()");
}
}
public class Derived extends Base {
public Derived () {}
public void foo() {
System.out.println("Derived.foo()");
}
}
And then, when i call those:
public class Running {
public static void main(String[] args) {
Base b = new Base();
Derived d = new Derived();
}
}
It outputs:
*Base.foo()*
*Derived.foo()*
So why, when it gets to derived constructor, it invokes the base constructor but uses the derived's method instead?
PS: If I mark those methods as private, it will print out:
*Base.foo()*
*Base.foo()*
This is how Java works read this page https://docs.oracle.com/javase/tutorial/java/IandI/super.html
And more specifically the Note here :
Note: If a constructor does not explicitly invoke a superclass
constructor, the Java compiler automatically inserts a call to the
no-argument constructor of the superclass. If the super class does not
have a no-argument constructor, you will get a compile-time error.
Object does have such a constructor, so if Object is the only
superclass, there is no problem.
So as you can see this is expected behavior. Even though you dot have a super call it is still automatically inserting it.
In regards of the second Question even though you are within the super constructor body still you Instance is of the Subtype. Also if you have some familiarity with C++ read this Can you write virtual functions / methods in Java?
The reason why it will write the base class when marking with private is because private methods are not Inherited. This is part of the Inheritance in Java topic.
To answer the question in your title. As I said, you cannot avoid the base class constructor being called (or one of the base class constructors if it has more than one). You can of course easily avoid the body of the constructor being executed. For example like this:
public class Base {
public Base(boolean executeConstructorBody) {
if (executeConstructorBody) {
foo();
}
}
public void foo() {
System.out.println("Base.foo()");
}
}
public class Derived extends Base {
public Derived() {
super(false);
}
public void foo() {
System.out.println("Derived.foo()");
}
}
public class Running {
public static void main(String[] args) {
Base b = new Base(true);
Derived d = new Derived();
}
}
Now the main method prints only:
Base.foo()
Because in the contructor of the Derived class it automatically gets injected a call to super(), if you do not add a call to super or to other constructor in the same class (using this).

method overriding with wrapper class

public class A
{
public void display(int i)
{
System.out.println("Inside A");
}
}
public class B extends A
{
public void display(Integer i)
{
System.out.println("Inside B");
}
}
public class starter
{
public static void main (String args[])
{
A a = new B();
a.display(5);
System.out.println("So now you know or not");
}
}
Output : Inside A
Can somebody explain this output? Normally child method should be called. How does Java behave here when we have a wrapper class and a primitive class using inheritance?
B#display does not override A#display, as the signature is different.
The fact ints can be boxed into Integers is not relevant here.
You could easily verify this by using the #Override annotation.
Since the reference type of a is A, the method is resolved with the exact match for a literal integer (your given 5 argument), which is int, therefore A#display is invoked.
You can still force the invocation of B#display by using this idiom (not for production code):
((B)a).display(new Integer(5));
This casts your a variable as a B type, hence allowing visibility of B's display method within context.
It also passes an Integer rather than an int, thus employing the signature of B's display method and allowing resolution to that method.

why base class method is invoked?

In the following code:
b.show("str");
//prints: from base
d.show("");
//prints: from str
Could one please explain why it's behaving differently?
I am wondering why Base b = new Sub(), that b.show() from base class would be invoked.
I am merely using DifferentClass, as an reference showing b.show(String) is called under an non-inheritance occasion.
public class TestClass {
public static void main(String[] args) {
Base b = new Sub();
b.show("str");
DifferentClass d = new DifferentClass ();
d.show("");
}
}
class Base {
public void show(Object obj) {
System.out.println("from base");
}
}
class Sub extends Base {
public void show(String str) {
System.out.println("from sub");
}
}
class DifferentClass {
public void show(String str) {
System.out.println("from str");
}
public void show(Object obj) {
System.out.println("from obj");
}
}
Because of the reference type.
Base b = new Sub();
b.show("str");
Sub2 s2 = new Sub2();
s2.show("");
In that code, though b is an instance of Sub, the reference type of the variable is Base. Method overloading is evaluated at compile-time, not run-time. That matters because at compile time, once the new Sub() constructor runs and we assign the variable, the compiler is no longer aware of the concrete class. Only that it's a valid Base.
Why does this matter?
Because when the compiler tries to resolve b.show(String), there is no method on Base (the only type it knows of for sure for b) which takes a String, so it passes the string to the show(Object) method.
Sub does not over-ride the show(String) method (though Sub2 does).
By the way, the #Override annotation will help you with this: When do you use Java's #Override annotation and why?
You're invoking with a string so the method show() overloaded with string is called.
Maybe you did not realize that sub2 does not inherit??...
You declare your variable b to be of type Base, then you invoke show() on it. Since it has a show method which matches the signature, that is the method invoked.
Then you declare your variable s2 to be of type Sub2, and invoke show(String) on it. The runtime invokes that method since it matches.

How to access a static method via a class reference

class A {
public static void foo() {}
}
class B {
public static void foo() {}
}
I have Class clazz = A.class; or B.class;
How do I access this via "clazz" assuming it might be assigned either 'A' or 'B'
It is only possible to access those methods using reflection. You cannot reference a class directly, only an instance of type Class.
To use reflection to invoke methodname(int a, String b):
Method m = clazz.getMethod("methodname", Integer.class, String.class);
m.invoke(null, 1, "Hello World!");
See Class.getMethod() and Method.invoke()
You may want to think about your design again, to avoid the need to dynamically call static methods.
You can invoke a static method via reflection like this :
Method method = clazz.getMethod("methodname", argstype);
Object o = method.invoke(null, args);
Where argstype is an array of arguments type and args is an array of parameters for the call. More informations on the following links :
getMethod()
invoke()
In your case, something like this should work :
Method method = clazz.getMethod("foo", null);
method.invoke(null, null); // foo returns nothing
You cannot access static methods without an explicit reference to the class.
No inheritance here, sorry, so you must either do:
A.foo()
or
B.foo()
If you really need it, you will have to do a check:
Object o = .... // eith an A or B instance.
if( o instanceof A ) {
A.foo()
} else {
B.foo()
}
But why don't you just make those functions instance functions, and let them implement an interface?
Okey, you have a class object. Then do:
Class c = ...;
c.getMethod("foo").invoke(null); // null to invoke static methods
According to my lack of knowledge the need for the requested construct is given by the fact that an interface doesn't offer the possibility of static abstract methods. Here is an example:
public enum Cheese implements Yumy {
GOUDA(49),
ESROM(40),
HWARTI(38);
private int percentage;
private Cheese(int fat100) {...} constructor
public void yamyam() {...} // as in Yumy
public static Cheese getByFat(int fat100) {...} // no chance to be part
of interface
};
I hope this isn't making too many assumptions or deviating too far from your question, but if your two classes share a common supertype and creating an instance is tolerable then you can:
Implement a common interface
Create an instance of the object via myClass.newInstance() (class must have an empty constructor)
Call the static method from the instance object.
interface Foo {
void foo();
}
class A implements Foo {...}
class B implements Foo {...}
<T extends Foo> public void something(Class<T> clazz) {
T myInstance = clazz.newInstance();
myInstance.foo();
}
...
something(A.class);
It's a little bizarre but in my case it proved to be useful, and I began by asking the very same question that you did.

Categories

Resources