将一个对象复制到某些字段的另一种更改数据类型中

时间:2018-07-19 13:57:54

标签: java clone

我有两个Java对象,如下所示:

class A {
  int a;
  int b;
}

class B {
  int a;
  Double b;
}

A objA = new A();
objA.a = 5;
objA.b = 6;

我想将objA克隆到objB中,以便将字段b转换为 从objB访问时加倍,即

objB.b = 6.0
objB.a = 5

注意:

  • 类必须有所不同。
  • 类是如此之大,以至于个人复制和类型转换似乎不是一个很好的选择。
  • 我无法从A扩展B类,因为字段名称完全相同,除了少数字段的数据类型在B类中从int更改为Double之外。

3 个答案:

答案 0 :(得分:4)

frameworks在不同类的对象之间进行映射。查看评论。

如果您不想使用第三方库,则可以编写这些框架所提供内容的过度简化版本。

例如,如果字段的名称相同,并且区别仅在于类型,则可以编写一个method(A a, B b, Rules r),它将根据给定的规则将a映射到b 1

public static void copyFromAtoB(A a, B b, Map<String, Function<Object, Object>> rules) throws NoSuchFieldException, IllegalAccessException {
    for (Field f : B.class.getDeclaredFields()) {
        final String fName = f.getName();
        final Object aValue = A.class.getDeclaredField(f.getName()).get(a);

        f.set(b, rules.containsKey(fName) ? rules.get(fName).apply(aValue) : aValue);
    }
}

规则 2 告诉我们应该对字段应用什么功能才能正确设置值。

如果没有针对字段的规则,则假定类型兼容。

final A a = new A(5, 6);
final B b = new B();

final Map<String, Function<Object, Object>> rules = new HashMap<>();
rules.put("b", i -> Double.valueOf((int)i));  // int -> Double

copyFromAtoB(a, b, rules);

1 是的,这是一种反思方法-可能成本高昂且设计过度,但似乎很灵活。
2 规则定义不明确,因为我们采用Object并返回ObjectFunction<Object, Object>)。

答案 1 :(得分:2)

如果您按照注释之一的建议尝试使用Apache BeanUtils,则会看到它具有copyProperties方法,该方法可以在某种程度上转换您的类型。例如,您可以像示例中那样从int自动获取double。但是,如果这些属性确实不兼容,则会出现异常,并且似乎没有办法说您要跳过它。 我的方法是扩展BeanUtilsBean类并添加类似于copyProperties()的方法,但有一个额外的参数:一组例外属性:

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

import org.apache.commons.beanutils.BeanUtilsBean;

public class MyBeanUtilsBean extends BeanUtilsBean {

    public void copyPropertiesExcept(Object dest, Object orig, String... exceptProperties)
            throws IllegalAccessException, InvocationTargetException {
        PropertyDescriptor[] origDescriptors = getPropertyUtils().getPropertyDescriptors(orig);
        for (int i = 0; i < origDescriptors.length; i++) {
            String name = origDescriptors[i].getName();
            if ("class".equals(name)) {
                continue; // No point in trying to set an object's class
            }
            if (Arrays.asList(exceptProperties).contains(name)) {
                continue;
            }
            if (getPropertyUtils().isReadable(orig, name) && getPropertyUtils().isWriteable(dest, name)) {
                try {
                    Object value = getPropertyUtils().getSimpleProperty(orig, name);
                    copyProperty(dest, name, value);
                } catch (NoSuchMethodException e) {
                    // Should not happen
                }
            }
        }
    }
}

然后,您可以使用该方法复制除不同属性以外的所有属性:

import java.lang.reflect.InvocationTargetException;

public class B {

    // ...

    public static B fromA(A objA) {
        B objB = new B();

        // Copy common properties
        try {
            new MyBeanUtilsBean().copyPropertiesExcept(objB, objA, "d");
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        // Explicitly copy specific properties
        objB.setD(new IntWrapper(objA.getD()));

        return objB;
    }
}

您也可以尝试使用complete working example

答案 2 :(得分:-1)

我将为class B创建一个构造函数,该构造函数接受所需的类型并将其转换。

class B {
   int a;
   Double b;

   public B(int a, int b) {
     this.a = a;
     this.b = new Double(b);
   }
}