简体   繁体   中英

How to generate methods dynamically in Java

I was wondering, what if I have the following case:

public class MyObject<T> {
   private T myTObject;

   public void setMyTObject(T m) { 
       myTObject = m;
   } 

   public T getMyTObject() { 
       return myTObject;
   }
}

And now I want that class to react something like these:

MyObject<ObjectA> objA = new MyObject<ObjectA>();
ObjectA objAInstance = objA.getObjectA();

or

objA.setObjectA(otherObjectAInstance);

Is there a way to dynamically create methods based on T class name? Or should I better extend ObjectA to MyObject and create those methods using super.get/seMyObject()?

For clarification:

The idea is to have a getter and setter method generated dynamically so, if I create an instance of:

MyObject<A> objA = new MyObject<A>();

I would be able to call method:

objA.getA();

getA() will call internally getMyTObject() or just return myTObject

so MyObject may react based on T class and generate the corresponding method.

I have updated member attribute to differentiate from MyObject class, it may lead to confusion. also fixed Method return and parameter Type.

Update Answer is completely changed.

Sounds like you want to use something through reflection. The problem with truly dynamically generating the method names is that, as others have commented, it would have to be done in bytecode which means that other classes trying to use your dynamic classes don't have Java code to refer to. It can be done, but it would be a mess.

Instead, here's a possible solution using generics. Please note that this is something of a quick and dirty hack; I leave it to you to refine it. You define an interface with the getters and setters you want, with whatever you want them named:

package com.example.dcsohl;

public interface IntegerWrapper {

    public Integer getInteger();
    public void setInteger(Integer i);

}

And then, to use them, you use this class to do the heavy lifting. Note that the error checking isn't very good; for example, it doesn't check that "getFoo" at all corresponds to the name of the class being passed in; nor does it validate that the "foo" in "getFoo" matches the "setFoo" method. This is something you can improve on.

package com.example.dcsohl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyWrapper<T> implements InvocationHandler {

    Class<T> clazz = null;
    T myvalue = null;

    public static <W,T> W getInstance(Class<W> clazz, Class<T> clazz2) {
        ProxyWrapper<T> wrapper = new ProxyWrapper<T>();
        wrapper.setClass(clazz2);
        @SuppressWarnings("unchecked")
        W proxy = (W)Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] {clazz}, wrapper);
        return proxy;
    }

    private void setClass(Class<T> clazz) {
        this.clazz = clazz;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // getter has no arguments
        if (method.getName().startsWith("get") && (args == null || args.length == 0)) {
            return myvalue;
        } else if (method.getName().startsWith("set") && args.length == 1) {
            Object o = args[0];
            if (o.getClass().isAssignableFrom(clazz)) {
                @SuppressWarnings("unchecked")
                T val = (T)o;
                myvalue = val;
                return null;
            }
        } else {
            throw new Exception();
        }
        return null;
   }


}

Finally, to use it, here's a quick sample:

package com.example.dcsohl;

public class Main {

    public static void main(String[] args) {

        Integer foo = 5;

        IntegerWrapper wrapper = ProxyWrapper.getInstance(IntegerWrapper.class, Integer.class);
        wrapper.setInteger(foo);

        Integer bar = wrapper.getInteger();
        System.out.println(bar);
    }

}

It seems like a lot of work just to avoid writing simple wrapper classes, and you'd be right, but reflection has its uses, and this is something of a sampler.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM