How can I override methods in Java when I create a

2020-05-19 08:05发布

问题:

In Java, is it possible to override methods in a class that you create using reflection? For example, say I have the following class:

public class MyObject
{
    public String foo, bar;

    public MyObject(String foo)
    {
        this.foo = foo;
        this.bar = foo + "bar";
    }

    public void setBar(String bar)
    {
        this.bar = bar;
    }
}

And in one class I want to create it directly and override its setBar method as follows:

MyObject obj = new MyObject("something")
{
    @Override
    public void setBar(String bar)
    {
        this.bar = this.foo;
    }
};

Is there a way to override a method in this same manner using reflection? Maybe something like this? :

Class<?> _class = Class.forName("com.example.MyObject");
Constructor<?> _constructor = _class.getConstructor(new Class<?>[]{String.class});
Method m = _class.getMethod("setBar", new Class<?>[]{String.class});
Object obj = _constructor.newInstance("Foo String")
{
    m = new Method(new Class<?>[]{String.class})
    {
        System.out.println("Foobar");
    }
};

If not, are there other ways of doing this, or an external library that could help? I am looking for way to add listeners to a setter method in order to change binded values.

回答1:

No, it's not possible in the way of your example.

In your example, the Java compiler will create two separate classes:

MyObject.class
MyObject$1.class

The latter being the one with the overridden method. In this case, it's an anonymous inner class (See Java tutorial documentation)

But there is more complex solution involving bytecode weaving libraries. Libraries such as cglib, asm, javassist etc. give you a facility to dynamically create new classes at runtime and load them.

Javassist has a tutorial on how to add methods to classes at runtime. It should be possible to adapt it to add/override the method, something like this:

CtClass origClazz = ClassPool.getDefault().get("org.example.MyObject");
CtClass subClass = ClassPool.getDefault().makeClass(cls.getName() + "New", origClazz);
CtMethod m = CtNewMethod.make(
             "public void setBar(String bar) { this.bar = bar; }",
             subClass );
subClass .addMethod(m);
Class clazz = cc.toClass();


回答2:

If you're returning an object of an interface type, you can use Proxy.newProxyInstance to get an instance of an interface that dynamically sends method invocations to an InvocationHandler object which you can write to do whatever custom behavior you want.



回答3:

No, what you are asking for is something like runtime compilation. While not impossible it certainly isn't something that the reflection API provides.