复制java中类似类之间的字段

时间:2010-12-09 04:56:19

标签: java

我有一对类,其中一个字段是另一个字段的子集,超集类的getter都是可预测命名的(getFoo())。有没有办法有效地复制从超集类到子集类的所有公共字段,或者至少自动生成代码来执行此操作。

我应该注意:

  • 由于各种原因,我无法编辑超集类,也无法全部使用它们以避免必须进行数据复制。
  • 我可以在子集类中创建新方法,但我无法更改它们的字段。
  • 我们有很多这样的对,有些类有很多字段,所以手工做这件事至少可以说是笨拙的。
  • 一位同事提出了一种创建泛型复制方法的方法,该方法使用java反射来获取任意两个类,以字符串形式迭代,执行字符串操作以确定getter名称,然后执行它以自动设置子集类中的字段。这很糟糕,但似乎有效。我真的希望有更好的方法。

编辑:一些简单的代码

public class SuperClass {
  private int foo;
  private int bar;
  private float bat;
  public int getFoo() { return foo; }
  public int getBar() { return bar; }
  public float getBat() { return bat; }
}

public class SubClass {
  private int foo;
  private float bat;
}

//wanted
public static copySuperFieldsToSubMethod(Object super, Object sub) { ??? }

// also acceptable would be some way to autogenerate all the assignment 
// functions needed

7 个答案:

答案 0 :(得分:12)

您可以使用Spring Framework中的BeanUtils类来执行此操作。它可能不一定比基于反射的技术更有效,但编码肯定很简单。我希望您需要做的就是:

BeanUtils.copyProperties(source, target);

此方法的Javadoc位于 http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/BeanUtils.html#copyProperties(java.lang.Object,%20java.lang.Object)

如果这不合适,您还可以考虑在Spring Framework中使用BeanWrapper / BeanWrapperImpl来迭代类的属性。这比使用低级反射API更简单。

答案 1 :(得分:3)

与第一个答案类似,但要澄清 - 不需要弹簧。 Commons BeanUtils.copy属性(Object dest,Object orig)

http://commons.apache.org/beanutils/api/org/apache/commons/beanutils/BeanUtils.html#copyProperties(java.lang.Object,%20java.lang.Object)

答案 2 :(得分:2)

如果您希望有效地完成任务(在运行时性能方面),那么使用getter和setter手动编写副本是可行的方法。除非getter或setter方法有些奇怪,否则它们的内部将被内联,以便它们与字段分配一样快。

反射方法(例如使用像BeanUtils这样的现有类)编码较少,但可能比以简单方式调用getter和setter慢一个数量级。如果你试图自己实现这个,你可能会发现自己有更多的工作而不是你讨价还价,特别是如果你的反射副本类/方法必须处理重载方法,继承,价值转换,装箱/拆箱等等。

使用代码生成方法,您需要平衡实现代码生成(使用您选择的任何技术)的工作量和复杂性,以及手动编写复制方法的工作量。在20个课程之前,您可能不会使用代码生成方法实现收支平衡......如果您不熟悉该技术,可能会更多。

答案 3 :(得分:2)

要根据字段而不是getter和setter进行复制,您可以使用Spring ReflectionUtils.shallowCopyFieldState()

答案 4 :(得分:1)

我会编写一个简单的java工具来自动生成类的源代码,这些类可以使用超集中的公共字段填充子集字段。此工具将使用反射来获取getter和setter方法的名称。其余的是(普通的)String操作,用于在内存中“写”源文件并将其存储到*.java文件中。编译所有这些自动生成的文件,并将类文件添加到类路径中。

课程可能如下所示:

class AClassToBClassPopulator implements Populator {
   @Overwrite
   public void populate(Object superSet, Object subSet) {
      subSet.setFieldA(superSet.getFieldA());
      subSet.setFieldB(superSet.getFieldB());
      // .. and so on. The method body is created through reflection
   }
}

答案 5 :(得分:0)

您是否可以从应用中提供一些示例代码,说明您在帖子中提到的方案? 现在反射似乎是最好的方法,因为它允许你在运行时检查类成员。

答案 6 :(得分:0)

这显然是Java反思的任务,而其他人已经建议有效,虽然可能有点重量级的解决方案,这里还有一个:

大约一年前,我写了一个名为BeanPropertyController的小型JavaBean属性修饰符库。虽然我没有特别向任何人推荐它,但我确实认为库的同名类( see source )可以作为参考来采用类似的功能来满足您的需求。作为一个简单的例子,这里是我如何使用BPC(差不多!)你所要求的:

// somewhere in code...
SuperClass a = new SuperClass();
a.foo = 101;
a.bar = 102;
a.bat = 103f;

SubClass b = new SubClass();
b.foo = 201;
b.bat = 202f;

BeanPropertyController fromB = BeanPropertyController.of(b, ExtractionDepth.QUESTIMATE);
BeanPropertyController toA = BeanPropertyController.of(a, ExtractionDepth.QUESTIMATE);

// This is where the magic happens:
for (String propertyName : fromB.getPropertyNames()) {
    toA.mutate(propertyName, fromB.access(propertyName));
}
a = (SuperClass) toA.getObject();
b = (SubClass) fromB.getObject();

System.out.println("SuperClass' foo="+a.foo+" bar="+a.bar+" bat="+a.bat);
System.out.println("SubClass' foo="+b.foo+" bat="+b.bat);

打印出来

SuperClass' foo=201 bar=102 bat=202.0
SubClass' foo=201 bat=202.0

所以,我建议您转到我链接的网址,并根据您的需求调整这段代码。我很确定你不需要我包含的各种实例化方法,默认值提供者等。是的,可以认为BPC已被弃用。