java 在java中的相似类之间复制字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4394978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Copy fields between similar classes in java
提问by Dusty
I have pairs of classes where the fields of one is a subset of the fields of another and the getters of the superset classes are all predictably named (getFoo()
). Is there some way to efficientlycopy all the common fields over from the superset class to the subset class, or at least auto-generate the code to do so.
我有成对的类,其中一个的字段是另一个字段的子集,并且超集类的 getter 都可预测地命名为 ( getFoo()
)。有没有办法有效地将所有公共字段从超集类复制到子集类,或者至少自动生成代码来这样做。
I should note that:
我应该注意的是:
- For various reasons, I can't edit the superset classes, nor can I just use them throughout to avoid having to do the data copy.
- I can potentially create new methods in the subset classes, but I can't change their fields.
- We have dozens of these pairs, and some of the classes have many many fields so doing this by hand is unwieldy to say the least.
- A colleague has come up with a method to create a generic copy method that uses java reflection to take any two classes, iterate through the fields as Strings, do string manipulation to determine the getter name, and then execute it to automatically set the field in the subset class. It's awful, but it appears to work. I'm really hoping there's a better way.
- 由于各种原因,我不能编辑超集类,也不能只使用它们来避免必须进行数据复制。
- 我可以在子集类中创建新方法,但我无法更改它们的字段。
- 我们有几十个这样的对,其中一些类有很多很多领域,所以至少可以说手工做这件事很笨拙。
- 有个同事想出了一个方法,创建一个通用的copy方法,使用java反射取任意两个类,将字段作为String进行迭代,做字符串操作来确定getter名称,然后执行它自动设置字段子集类。这很糟糕,但它似乎有效。我真的希望有更好的方法。
Edit: some simple code as requested
编辑:一些简单的代码要求
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
采纳答案by gutch
You could use the BeanUtils
class in the Spring Framework to do this. It may not necessarily be any more efficient than your reflection-based technique, but it's certainly simple to code. I expect that all you would need to do is:
您可以使用BeanUtils
Spring Framework 中的类来执行此操作。它可能不一定比基于反射的技术更有效,但它的编码肯定很简单。我希望您需要做的就是:
BeanUtils.copyProperties(source, target);
Javadoc for this method is available at http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/BeanUtils.html#copyProperties(java.lang.Object,%20java.lang.Object)
此方法的 Javadoc 可在 http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/BeanUtils.html#copyProperties(java.lang.Object,%20java.lang.Object)
If that doesn't suit, you could also consider using BeanWrapper
/ BeanWrapperImpl
in the Spring Framework to iterate through the properties of your classes. That would be simpler than using low-level reflection APIs.
如果这不合适,您还可以考虑在 Spring 框架中使用BeanWrapper
/BeanWrapperImpl
来遍历类的属性。这比使用低级反射 API 更简单。
回答by revdrjrr
Similar to the first answer, but to clarify - spring is not needed. Commons BeanUtils.copy properties(Object dest, Object orig)
类似于第一个答案,但要澄清 - 不需要弹簧。Commons BeanUtils.copy 属性(Object dest, Object orig)
回答by Alexander
To copy based on fields rather than getters and setters, you can use Spring's ReflectionUtils.shallowCopyFieldState().
要基于字段而不是 getter 和 setter 进行复制,您可以使用 Spring 的ReflectionUtils.shallowCopyFieldState()。
回答by Stephen C
If you want to the task efficiently (in terms of runtime performance), then hand coding the copy using getters and setters is the way to go. Unless there is something funky about the getter or setter methods, their bodies will be inlined so that they are as fast as doing field assignments.
如果您想高效地完成任务(在运行时性能方面),那么使用 getter 和 setter 对副本进行手动编码是可行的方法。除非 getter 或 setter 方法有什么奇怪的地方,否则它们的主体将被内联,以便它们与执行字段分配一样快。
The reflective approach (e.g. using an existing class like BeanUtils
) is less coding, but probably an order of magnitude slower than calling getters and setters in a simple way. If you try to implement this yourself, you may find yourself with more work than you bargained for, especially if your reflective copy class / method has to cope with overloaded methods, inheritance, value conversion, boxing/unboxing and so on.
反射方法(例如使用像 现有的类BeanUtils
)编码较少,但可能比以简单方式调用 getter 和 setter 慢一个数量级。如果您尝试自己实现这一点,您可能会发现自己的工作量超出了您的预期,特别是如果您的反射复制类/方法必须处理重载方法、继承、值转换、装箱/拆箱等。
With the code generation approach, you need to balance the effort and complexity of implementing the code generation (using whatever technology you choose) versus the effort of writing the copy methods by hand. You probably probably won't break even with the code generation approach before 20 classes ... and many more if you are not familiar with the technology.
使用代码生成方法,您需要平衡实现代码生成(使用您选择的任何技术)的工作量和复杂性与手动编写复制方法的工作量。您可能不会在 20 个类之前使用代码生成方法收支平衡……如果您不熟悉该技术,还有更多。
回答by Andreas Dolk
I'd write a simple java tool to autogenerate the source code for classes that can populate the the subsets fields with the common fields from superset. This tool will use reflection to get the names of the getter and setter methods. The rest are (trivial) String operations to "write" a source file in memory and store it to a *.java
file. Compile all this autogenerated files and add the class files to the classpath.
我会编写一个简单的 java 工具来自动生成类的源代码,这些类可以使用超集中的公共字段填充子集字段。此工具将使用反射来获取 getter 和 setter 方法的名称。其余的是(琐碎的)字符串操作,用于在内存中“写入”源文件并将其存储到*.java
文件中。编译所有这些自动生成的文件并将类文件添加到类路径中。
The class could look like this:
该类可能如下所示:
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
}
}
回答by Anupam Saini
Can you provide some sample code from your app that depicts the scenario you have mentioned in your post? Right now reflection seems like the best way , since it lets you inspect the class members at runtime.
您能否从您的应用中提供一些示例代码来描述您在帖子中提到的场景?现在反射似乎是最好的方法,因为它可以让您在运行时检查类成员。
回答by Esko
This is obviously a task for Java's reflection and while others have already suggested valid although maybe a bit heavyweight solutions, here's one more:
这显然是 Java 反思的一项任务,虽然其他人已经提出了有效但可能有点重量级的解决方案,但这里还有一个:
About a year ago I wrote a smallish JavaBean property modifier library called BeanPropertyController. While I don't specifically recommend it to anyone, I do think that the namesake class of the library (see source) can be used as a reference to adopt similar functionality to your needs. As a quick example, here's how I used BPC to do (almost!) what you're asking:
大约一年前,我编写了一个名为BeanPropertyController的小型 JavaBean 属性修饰符库。虽然我没有特别向任何人推荐它,但我确实认为库的同名类(请参阅源代码)可以用作参考,以采用类似的功能来满足您的需求。举一个简单的例子,这是我如何使用 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);
This prints out
这打印出来
SuperClass' foo=201 bar=102 bat=202.0
SubClass' foo=201 bat=202.0
So, what I suggest is that you go to the URL I linked and adapt this piece of code to your needs. I'm quite sure you don't need the various instantiation methods, default value providers etc. which I've included. And yes, BPC can be considered to be deprecated.
因此,我建议您访问我链接的 URL 并根据您的需要调整这段代码。我很确定您不需要我包含的各种实例化方法、默认值提供程序等。是的,BPC 可以被视为已弃用。