【问题标题】:Copying one class's fields into another class's identical fields将一个类的字段复制到另一个类的相同字段中
【发布时间】:2012-08-10 11:08:50
【问题描述】:

我有这个问题。但是我很难解释,因为我不知道要使用的确切术语。希望有人能理解。我会尽力描述最好的。我觉得这和parsing有很大关系

假设有两个类。在这两个类中我都有一些变量,比如字符串(为了简单起见,变量类型可以是任何类型),它们具有相似的名称

Eg:
    class ClassA{
        String x,y,z;
    }

    class ClassB{
        String x,y,z;
    }

现在,我需要的是,我需要将一个类的变量值的值复制到其他类对应的变量中。

Eg:
    ClassA aa=new ClassA();
    ClassB bb=new ClassB();
    //set bb's variables
    aa.x=bb.x;
    aa.y=bb.y;
    aa.z=bb.z;

这样。

但请注意,我需要的不是上述方法。我希望有一种方法可以编写一个简单的方法,以便通过传递给它的名称来识别相关变量。然后它会做相应的赋值。

我想象的方法是这样的,

void assign(String val){        
    // aa.<val>=val
}

例如,如果您将bb.x 传递给assign(...) 方法,那么它将执行aa.x=bb.x 赋值。

希望这足够清楚。必须有更好的方法来解释这一点。如果有人知道,请编辑帖子(+标题)以使其更清晰(但请保存我的想法)..

如果有办法实现这一点,请告诉我。

谢谢!

【问题讨论】:

  • 你真的需要两节课吗?不能只是同一类的两个实例吗?然后你可以只使用 clone() 方法。
  • 你可以试试 Map 或 hashmap... 或者做一些反射。这类东西必须是专门构建的,所以为什么不与我们分享一个常见的用例呢?
  • @visionary 不。不能去克隆。上了两节课。 :(
  • @Shark 好吧,我的问题是寻求下面建议的 Jean-RémyRevy 和 SeanPatrickFloyd 之类的解决方案。不要与类名混淆。这是我能做的最好的解释。如果我尝试提供更多细节会很复杂。
  • 感谢@Shark,如果您能解释一下reflection,将不胜感激。我还没有遇到过..(你最好把它作为一个答案,因为这不喜欢扩展讨论:D)

标签: java parsing javabeans dozer


【解决方案1】:

推土机很好,请参阅 Jean-Remy 的回答。

此外,如果变量根据 JavaBeans 标准具有 getter 和 setter,那么有许多技术可以帮助您,例如Apache Commons / BeanUtils

示例代码(未测试):

final Map<String, Object> aProps = BeanUtils.describe(a);
final Map<String, Object> bProps = BeanUtils.describe(b);
aProps.keySet().retainAll(bProps.keySet());
for (Entry<String, Object> entry : aProps.entrySet()) {
    BeanUtils.setProperty(b,entry.getKey(), entry.getValue());
}

更新:

如果您没有 getter 和 setter,这里有一个快速技巧,只要字段具有通用名称和类型,就可以将字段值从一个类复制到另一个类。我没有测试过,但作为起点应该没问题:

public final class Copier {

    public static void copy(final Object from, final Object to) {
        Map<String, Field> fromFields = analyze(from);
        Map<String, Field> toFields = analyze(to);
        fromFields.keySet().retainAll(toFields.keySet());
        for (Entry<String, Field> fromFieldEntry : fromFields.entrySet()) {
            final String name = fromFieldEntry.getKey();
            final Field sourceField = fromFieldEntry.getValue();
            final Field targetField = toFields.get(name);
            if (targetField.getType().isAssignableFrom(sourceField.getType())) {
                sourceField.setAccessible(true);
                if (Modifier.isFinal(targetField.getModifiers())) continue;
                targetField.setAccessible(true);
                try {
                    targetField.set(to, sourceField.get(from));
                } catch (IllegalAccessException e) {
                    throw new IllegalStateException("Can't access field!");
                }
            }
        }
    }

    private static Map<String, Field> analyze(Object object) {
        if (object == null) throw new NullPointerException();

        Map<String, Field> map = new TreeMap<String, Field>();

        Class<?> current = object.getClass();
        while (current != Object.class) {
            for (Field field : current.getDeclaredFields()) {
                if (!Modifier.isStatic(field.getModifiers())) {
                    if (!map.containsKey(field.getName())) {
                        map.put(field.getName(), field);
                    }
                }
            }
            current = current.getSuperclass();
        }
        return map;
    }
}

调用语法:

Copier.copy(sourceObject, targetObject);

【讨论】:

  • 感谢@SeanPatrickFloyd。是的,如果我有getterssetters 这将派上用场。嗯,我会考虑的。但我现在想尝试一下dozer 的东西..
  • @Anubis 我已经为字段添加了解决方案
  • @Shark 是的,但请注意:编码需要 10 分钟。不要在生产中使用它
  • 我的意思更多是为了证明我在下面建议的概念。但是,嘿,如果它有效... :)
  • 效果很好!它缺少“current = current.getSuperclass();”在“while(当前!= Object.class)”循环的末尾。没有这个,它会进入一个无限循环。
【解决方案2】:

您听说过推土机吗? :http://dozer.sourceforge.net/

推土机

Dozer 是一个 Java Bean 到 Java Bean 的映射器,它递归地将数据从一个对象复制到另一个对象。通常,这些 Java Bean 将具有不同的复杂类型。

Dozer 支持简单属性映射、复杂类型映射、双向映射、隐式-显式映射以及递归映射。这包括映射集合属性,也需要在元素级别进行映射。

Dozer 允许您映射 Java Bean:

  • 使用它们的名称(隐式映射),即将 ClassA.x 映射到 ClassB.x
  • 提供使用(非常简单的)xml 或注释配置映射不同名称的不同结构(显式映射)的能力。

这是图书馆网站上的一个 XML 示例:

<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://dozer.sourceforge.net
          http://dozer.sourceforge.net/schema/beanmapping.xsd">
          
  <mapping> 
    <class-a>org.dozer.vo.TestObject</class-a>
    <class-b>org.dozer.vo.TestObjectPrime</class-b>   
    <field>
      <a>one</a>
      <b>onePrime</b>
    </field>
  </mapping>  

      <!-- SNIP ... -->

</mappings>

这会将对象 org.dozer.vo.TestObject 映射到 TestObjectPrime,将所有相同的变量(如您的情况)和变量 TestObjectFoo.oneFoo 映射到 TestObjectFooPrime.oneFooPrime。

很好,不是吗?

【讨论】:

  • 感谢您的回答。是的,我从未听说过dozer。看起来很棒。我会尝试那个并给出反馈。谢谢!
【解决方案3】:

新答案。

我建议研究 Dover,因为它看起来很简单。

第二个选项是将类序列化为 XML 并仅在匹配的成员上反序列化为目标类。

我在评论中提到的第三个选项是使用反射 - http://java.sun.com/developer/technicalArticles/ALT/Reflection/

这种技术允许一个很好的设计模式,称为 Introspection - Java introspection and reflection 反过来允许您发现某个类的成员...

现在,话虽如此,我们只需“发现” ClassA 的成员,用他们的名字填充一个 ArrayList,发现 ClassB 的成员,用他们的名字填充另一个 ArrayList,然后复制相交集的值。至少这是我的想法。

【讨论】:

  • 这应该是一个评论,充其量
【解决方案4】:

here。只需使用BeanUtils.copyProperties(newObject, oldObject);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-09
    • 1970-01-01
    • 2019-06-08
    相关资源
    最近更新 更多