java—通过反射将所有值从一个类中的字段复制到另一个类中

lymnna71  于 2021-07-05  发布在  Java
关注(0)|答案(18)|浏览(442)

我有一个类,基本上是另一个类的副本。

public class A {
  int a;
  String b;
}

public class CopyA {
  int a;
  String b;
}

我所做的就是把课堂上的价值观 A 进入 CopyA 发送前 CopyA 通过网络服务呼叫。现在我想创建一个反射方法,基本上从类中复制所有相同(按名称和类型)的字段 A 上课 CopyA .
我该怎么做?
这是我目前所拥有的,但并不完全有效。我认为这里的问题是,我试图在我循环通过的场上设置一个场。

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();
            }

        }
    }

我相信一定有人已经做了这件事

ej83mcc0

ej83mcc016#

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;
    }
zzlelutf

zzlelutf17#

orika是一个简单的、更快的beanMap框架,因为它是通过字节码生成的。它做嵌套Map和不同名称的Map。有关更多详细信息,请检查此处示例Map可能看起来很复杂,但对于复杂的场景,它将很简单。

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);
zed5wv10

zed5wv1018#

mladen的基本想法奏效了(谢谢),但是需要一些修改才能变得强大,所以我在这里提供了它们。
唯一应该使用这种类型的解决方案的地方是,如果您想克隆对象,但不能,因为它是托管对象。如果您有幸拥有所有字段都具有100%无副作用设置器的对象,那么您肯定应该改用beanutils选项。
在这里,我使用lang3的实用方法来简化代码,因此如果粘贴它,必须首先导入apache的lang3库。
复制代码

static public <X extends Object> X copy(X object, String... skipFields) {
        Constructor constructorToUse = null;
        for (Constructor constructor : object.getClass().getConstructors()) {
            if (constructor.getParameterTypes().length == 0) {
                constructorToUse = constructor;
                constructorToUse.setAccessible(true);
                break;
            }
        }
        if (constructorToUse == null) {
            throw new IllegalStateException(object + " must have a zero arg constructor in order to be copied");
        }
        X copy;
        try {
            copy = (X) constructorToUse.newInstance();

            for (Field field : FieldUtils.getAllFields(object.getClass())) {
                if (Modifier.isStatic(field.getModifiers())) {
                    continue;
                }

                //Avoid the fields that you don't want to copy. Note, if you pass in "id", it will skip any field with "id" in it. So be careful.
                if (StringUtils.containsAny(field.getName(), skipFields)) {
                    continue;
                }

                field.setAccessible(true);

                Object valueToCopy = field.get(object);
                //TODO add here other special types of fields, like Maps, Lists, etc.
                field.set(copy, valueToCopy);

            }

        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            throw new IllegalStateException("Could not copy " + object, e);
        }
        return copy;
}

相关问题