如果提供字段名称,如何一般填充对象?

时间:2016-01-17 20:34:31

标签: java oop design-patterns

我需要在方法中创建和填充对象。唯一的信息是成员字段名称(作为字符串传递)以及该字段的相关值(作为Object传递)。考虑到性能,最合适的设计模式是什么? - 反思,如果有罚款,则不是首选方法。

更新
要设置的值来自一个对象,该对象充当值的生成器,该对象具有一组返回特定​​字段的适当值的方法。例如。对于会员Double x;,它将是generator.getX()

2 个答案:

答案 0 :(得分:1)

将所有getter复制到所有可用setter的简单函数如下。通过一些更多的工作,您可以缓存此信息并加快速度,但它可能足够快。

public static <T> T copyTo(Object from, T to) {
    for(Method m : to.getClass().getMethods()) {
        if (!m.getName().startsWith("set") || m.getParameterCount() != 1)
            continue;
        try {
            Method getter = from.getClass().getMethod("g" + m.getName().substring(1));
            m.invoke(to, getter.invoke(from));
        } catch (NoSuchMethodException ignored) {
            // ignored
        } catch (InvocationTargetException | IllegalAccessException e) {
            throw new AssertionError(e);
        }
    }
    return to;
}

注意:只有匹配的getter和setter的字段才会尝试从一个字段复制到另一个字段。

public static void main(String[] args) {
    One orig = new One(1, "hi", 3);
    One to = new One();
    One copy = copyTo(orig, to);
    System.out.println(to);
}

static class One {
    int x;
    String y;
    double z;

    public One() {
    }

    public One(int x, String y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public String getY() {
        return y;
    }

    public void setY(String y) {
        this.y = y;
    }

    public double getZ() {
        return z;
    }

    public void setZ(double z) {
        this.z = z;
    }

    @Override
    public String toString() {
        return "One{" +
                "x=" + x +
                ", y='" + y + '\'' +
                ", z=" + z +
                '}';
    }
}

打印

One{x=1, y='hi', z=3.0}

如果要通常创建对象,则需要使用反射。

唯一的选择是字节码生成,实现起来要复杂得多,只能节省一小部分微秒。

为了节省微秒,需要多少天才能实现此目的?

答案 1 :(得分:1)

如果您知道对象的类名,那么您可以做的是:

    public Object populate(String className,String fieldName,Object value) throws Exception{
        Class clazz = Class.forName(className);
        Object o = null;
        for(Field f: clazz.getFields()){
            if(f.getName().equals(fieldName)){
                o =  clazz.getConstructor().newInstance();//default constructor if it exists
                f.set(o, value);
                break;
            }
        }
        return o;
    }

编辑: 既然你知道了这个类(有问题的评论)那么你可以使用的是我用这个改变写的函数,而不是className参数:

Class clazz = Class.forName(YourClass.class.getName()); 

EDIT2: 如果我理解更新,您询问如何知道调用哪个方法来获取值。 在您的生成器类中,您可以获取它具有的方法列表。然后,如果您的方法名为getFieldName(),则可以在具有字段名称后找到名为getFiledName的方法。 例如:

    for(Method m:GeneratorClass.class.getMethods()){
        System.out.println(m.getName());
        //analyze method name and field name to determine which method to call
        //..
        boolean callThis = true;//result of analysis
        if(callThis){
            //Object value = m.invoke(obj);
            //obj==generator
        }
    }