Java 通过反射将一个类中字段的所有值复制到另一个类中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1667854/
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 all values from fields in one class to another through reflection
提问by Shervin Asgari
I have a class which is basically a copy of another class.
我有一个课程,它基本上是另一个课程的副本。
public class A {
int a;
String b;
}
public class CopyA {
int a;
String b;
}
What I am doing is putting values from class A
into CopyA
before sending CopyA
through a webservice call. Now I would like to create a reflection-method that basically copies all fields that are identical (by name and type) from class A
to class CopyA
.
我正在做的是在通过网络服务调用发送之前将类中的值A
放入。现在我想创建一个反射方法,它基本上将所有相同(按名称和类型)的字段从 class 复制到 class 。CopyA
CopyA
A
CopyA
How can I do this?
我怎样才能做到这一点?
This is what I have so far, but it doesn't quite work. I think the problem here is that I am trying to set a field on the field I am looping through.
这是我到目前为止所拥有的,但它并不完全有效。我认为这里的问题是我试图在我正在循环的字段上设置一个字段。
private <T extends Object, Y extends Object> void copyFields(T from, Y too) {
Class<? extends Object> fromClass = from.getClass();
Field[] fromFields = fromClass.getDeclaredFields();
Class<? extends Object> tooClass = too.getClass();
Field[] tooFields = tooClass.getDeclaredFields();
if (fromFields != null && tooFields != null) {
for (Field tooF : tooFields) {
logger.debug("toofield name #0 and type #1", tooF.getName(), tooF.getType().toString());
try {
// Check if that fields exists in the other method
Field fromF = fromClass.getDeclaredField(tooF.getName());
if (fromF.getType().equals(tooF.getType())) {
tooF.set(tooF, fromF);
}
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I am sure there must be someone that has already done this somehow
我相信一定有人已经以某种方式这样做了
采纳答案by Greg Case
回答by Ruben Bartelink
UPDATE Nov 19 2012: There's now a new ModelMapper projecttoo.
2012 年 11 月 19 日更新:现在也有一个新的 ModelMapper 项目。
回答by Shaun F
Yeah or the BeanUtils from Apache Jakarta.
是的,或者来自 Apache Jakarta 的 BeanUtils。
回答by David Moles
The first argument to tooF.set()
should be the target object (too
), not the field, and the second argument should be the value, not the field the value comes from. (To get the value, you need to call fromF.get()
-- again passing in a target object, in this case from
.)
第一个参数tooF.set()
应该是目标对象 ( too
),而不是字段,第二个参数应该是值,而不是值来自的字段。(要获取该值,您需要调用fromF.get()
-- 再次传入目标对象,在本例中为from
。)
Most of the reflection API works this way. You get Field
objects, Method
objects, and so on from the class, not from an instance, so to use them (except for statics) you generally need to pass them an instance.
大多数反射 API 都是这样工作的。您可以从类中获取Field
对象、Method
对象等,而不是从实例中获取,因此要使用它们(静态除外),您通常需要向它们传递一个实例。
回答by Supun Sameera
BeanUtils will only copy public fields and is a bit slow. Instead go with getter and setter methods.
BeanUtils 只会复制公共字段,速度有点慢。而是使用 getter 和 setter 方法。
public Object loadData (RideHotelsService object_a) throws Exception{
Method[] gettersAndSetters = object_a.getClass().getMethods();
for (int i = 0; i < gettersAndSetters.length; i++) {
String methodName = gettersAndSetters[i].getName();
try{
if(methodName.startsWith("get")){
this.getClass().getMethod(methodName.replaceFirst("get", "set") , gettersAndSetters[i].getReturnType() ).invoke(this, gettersAndSetters[i].invoke(object_a, null));
}else if(methodName.startsWith("is") ){
this.getClass().getMethod(methodName.replaceFirst("is", "set") , gettersAndSetters[i].getReturnType() ).invoke(this, gettersAndSetters[i].invoke(object_a, null));
}
}catch (NoSuchMethodException e) {
// TODO: handle exception
}catch (IllegalArgumentException e) {
// TODO: handle exception
}
}
return null;
}
回答by Priyank Doshi
I think you can try dozer. It has good support for bean to bean conversion. Its also easy to use. You can either inject it into your spring application or add the jar in class path and its done.
我想你可以试试推土机。它对 bean 到 bean 的转换有很好的支持。它也很容易使用。您可以将它注入到您的 spring 应用程序中,也可以将 jar 添加到类路径中并完成。
For an example of your case :
以您的情况为例:
DozerMapper mapper = new DozerMapper();
A a= new A();
CopyA copyA = new CopyA();
a.set... // set fields of a.
mapper.map(a,copyOfA); // will copy all fields from a to copyA
回答by Nagappan
Orika's is simple faster bean mapping framework because it does through byte code generation. It does nested mappings and mappings with different names. For more details, please check hereSample mapping may look complex, but for complex scenarios it would be simple.
Orika 是一个简单的快速 bean 映射框架,因为它通过字节码生成来完成。它执行嵌套映射和具有不同名称的映射。有关更多详细信息,请查看此处示例映射可能看起来很复杂,但对于复杂的场景,它会很简单。
MapperFactory factory = new DefaultMapperFactory.Builder().build();
mapperFactory.registerClassMap(mapperFactory.classMap(Book.class,BookDto.class).byDefault().toClassMap());
MapperFacade mapper = factory.getMapperFacade();
BookDto bookDto = mapperFacade.map(book, BookDto.class);
回答by Mladen Adamovic
I didn't want to add dependency to another JAR file because of this, so wrote something which would suit my needs. I follow the convention of fjorm https://code.google.com/p/fjorm/which means that my generally accessible fields are public and that I don't bother to write setters and getters. (in my opinion code is easier to manage and more readable actually)
由于这个原因,我不想向另一个 JAR 文件添加依赖项,所以写了一些适合我需要的东西。我遵循 fjorm https://code.google.com/p/fjorm/的约定,这意味着我通常可访问的字段是公开的,而且我不会费心编写 setter 和 getter。(在我看来,代码实际上更易于管理且更具可读性)
So I wrote something (it's not actually much difficult) which suits my needs (assumes that the class has public constructor without args) and it could be extracted into utility class
所以我写了一些适合我需要的东西(实际上并不难)(假设该类具有没有 args 的公共构造函数)并且它可以被提取到实用程序类中
public Effect copyUsingReflection() {
Constructor constructorToUse = null;
for (Constructor constructor : this.getClass().getConstructors()) {
if (constructor.getParameterTypes().length == 0) {
constructorToUse = constructor;
constructorToUse.setAccessible(true);
}
}
if (constructorToUse != null) {
try {
Effect copyOfEffect = (Effect) constructorToUse.newInstance();
for (Field field : this.getClass().getFields()) {
try {
Object valueToCopy = field.get(this);
//if it has field of the same type (Effect in this case), call the method to copy it recursively
if (valueToCopy instanceof Effect) {
valueToCopy = ((Effect) valueToCopy).copyUsingReflection();
}
//TODO add here other special types of fields, like Maps, Lists, etc.
field.set(copyOfEffect, valueToCopy);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(Effect.class.getName()).log(Level.SEVERE, null, ex);
}
}
return copyOfEffect;
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Logger.getLogger(Effect.class.getName()).log(Level.SEVERE, null, ex);
}
}
return null;
}
回答by Darkhan Iskakov
Without using BeanUtils or Apache Commons
public static <T1 extends Object, T2 extends Object> void copy(T1 origEntity, T2 destEntity) throws IllegalAccessException, NoSuchFieldException { Field[] fields = origEntity.getClass().getDeclaredFields(); for (Field field : fields){ origFields.set(destEntity, field.get(origEntity)); } }
不使用 BeanUtils 或 Apache Commons
public static <T1 extends Object, T2 extends Object> void copy(T1 origEntity, T2 destEntity) throws IllegalAccessException, NoSuchFieldException { Field[] fields = origEntity.getClass().getDeclaredFields(); for (Field field : fields){ origFields.set(destEntity, field.get(origEntity)); } }
回答by db80
If you have spring in the dependencies you can also use org.springframework.beans.BeanUtils.
如果您在依赖项中有 spring,您还可以使用org.springframework.beans.BeanUtils。
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/BeanUtils.html
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/BeanUtils.html