【问题标题】:How to generate methods dynamically in Java如何在 Java 中动态生成方法
【发布时间】:2015-05-29 17:50:58
【问题描述】:

我想知道,如果我有以下情况怎么办:

public class MyObject<T> {
   private T myTObject;

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

   public T getMyTObject() { 
       return myTObject;
   }
}

现在我希望该类做出如下反应:

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

objA.setObjectA(otherObjectAInstance);

有没有办法根据 T 类名动态创建方法? 还是我应该更好地将 ObjectA 扩展到 MyObject 并使用 super.get/seMyObject() 创建这些方法?

澄清:

想法是动态生成getter和setter方法 所以,如果我创建一个实例:

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

我可以调用方法:

objA.getA();

getA() 将在内部调用 getMyTObject() 或只返回 myTObject

所以 MyObject 可能会根据 T 类做出反应并生成相应的方法。

我已更新成员属性以区别于 MyObject 类,这可能会导致混淆。还修复了方法返回和参数类型。

【问题讨论】:

  • 嗯,generate classes and methods on the fly with byte code generators 是可以的,但这并不容易。还有一个使用反射的Proxy 类。但总的来说,如果可以的话,最好使用扩展。
  • 我认为应该注意java反射..
  • 我没有读到任何关于你为什么要这样做的信息?仅仅因为您可以或者是您发现它是更好的 getter 和 setter 命名约定以依赖于实际的泛型类型的唯一原因?在后一种情况下,只需忘记它,没有人这样做,这不值得,只需为您的 getter 和 setter 使用通用名称,一切都很好。确实没有任何好处,所有现代 IDE 都会告诉您返回和设置的具体对象类型。查看标准 Java API 和通用类,如 List、Map 等。

标签: java generics methods


【解决方案1】:

更新答案完全改变了。

听起来您想通过反射来使用某些东西。真正动态生成方法名称的问题在于,正如其他人所评论的那样,它必须在字节码中完成,这意味着尝试使用您的动态类的其他类没有 Java 代码可以引用。它可以完成,但会一团糟。

相反,这是一个使用泛型的可能解决方案。请注意,这是一种快速而肮脏的 hack;我把它留给你来完善它。你用你想要的 getter 和 setter 定义一个接口,用你想要的名字:

package com.example.dcsohl;

public interface IntegerWrapper {

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

}

然后,要使用它们,您可以使用这个类来完成繁重的工作。请注意,错误检查不是很好;例如,它根本不检查“getFoo”是否与传入的类的名称相对应;它也不会验证“getFoo”中的“foo”是否与“setFoo”方法匹配。这是您可以改进的地方。

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;
   }


}

最后,要使用它,这里有一个简单的示例:

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);
    }

}

为了避免编写简单的包装类似乎需要做很多工作,而且你是对的,但是反射有它的用途,这是一个采样器。

【讨论】:

  • 据我了解,这并不能回答他的问题。他想要做的是让方法本身的名称为getObjectA() 而不是getT()getMyObject()
  • 哦。你说得对,我忽略了这一点。过于关注方法签名而不是名称。
  • 对不起,我写错了方法名称,我已经相应地解决了这个问题,NoseKnowsAll 明白了。最后,我想避免创建一堆扩展为 MyObject 的类,这些类只实现 getTObject()/setTObject(T arg)
  • 好的,我完全改变了我的答案,采用基于反射的方法。部分是因为我不知道如何做花哨的字节码,部分是因为我在上面解释的原因会更实用。
  • 谢谢大家的光!将分析您的建议。
猜你喜欢
  • 2012-01-30
  • 2019-08-29
  • 1970-01-01
  • 1970-01-01
  • 2018-02-22
  • 2015-04-04
  • 2016-06-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多