复制并在类之间添加字段

时间:2015-01-03 09:36:50

标签: java

我想知道以下情况是否可行。

有两个类(源和目标),在代码中我可以这样做:

public class Source{

   private String fieldA;
   private String fieldB;

   public Source(){ ... }
}

...

public class Destination{

   public Destination(Source src){ ... }
}

Source src = new Source();
Destination dest = new Destination(src);
dest.fieldA = "test";
dest.fieldB = "test";

所以我的意思是我有两个类,一个名为Source,包含(私有)字段,另一个名为Destination,没有字段。在创建这些类的两个对象并将Source传递到Destination的构造函数后,我希望能够将Source的字段复制/复制到Destination。< / p>

无论是否使用Reflection,这样的事情都可以在Java中实现吗?如果可能的话,有人可以给我一个我可以开始的小例子。

5 个答案:

答案 0 :(得分:3)

要实现此目的的hackish版本是将所有字段添加到Map。可以将字段从源对象复制到目标对象,并且字段名称可以是键。有点像这样:

public class FieldAccessor {
    public static class Destination {
        private final Map<String, Object> fields = new HashMap<>();

        public Destination(Object o) {
            final Set<Field> accessibleFields = Arrays.stream(o.getClass().getDeclaredFields())
                    .map(field -> {
                        field.setAccessible(true);
                        return field;
                    })
                    .collect(Collectors.toSet());

            accessibleFields.forEach(field -> {
                try {
                    fields.put(field.getName(), field.get(o));
                } catch (IllegalAccessException e) {
                    throw new IllegalStateException("Unable to access field", e);
                }
            });
        }

        public Set<String> fieldNames() {
            return fields.keySet();
        }

        public Optional<Object> fieldValue(String fieldName) {
            return Optional.ofNullable(fields.get(fieldName));
        }
    }

    public static class Source {
        private final String fieldA;
        private final Integer fieldB;
        private final int fieldC;

        public Source(String fieldA, Integer fieldB, int fieldC) {
            this.fieldA = fieldA;
            this.fieldB = fieldB;
            this.fieldC = fieldC;
        }

        public String getFieldA() {
            return fieldA;
        }

        public Integer getFieldB() {
            return fieldB;
        }

        public int getFieldC() {
            return fieldC;
        }
    }

    @Test
    public void testFields() {
        Destination destination = new Destination(new Source("Abc", 123, 456));

        destination.fieldNames().stream().forEach(fieldName -> {
            System.out.println("Fieldname: " + fieldName + ", value: " + destination.fieldValue(fieldName).get());
        });
    }
}

有关详细信息,请查看this SO

但是, 真正的生产代码中不是我会使用的。相反,我会使用某种序列化,例如,使用Jackson

答案 1 :(得分:1)

所以你想在一个对象中动态创建字段?这在Java中是不可能直接实现的。如果您只想复制接口的方法,那么答案就是使用JDK代理。如果符合以下条件,可能仍有意义:

  • 您接受仅在Destination class
  • 中使用getter和setter
  • Source类实现了一个定义要复制的setter和getter的接口

如果您不能接受这些限制,则必须查看CGLIB个代理或Javassist,即在加载时动态修改已编译类对象的字节码的库。它是一个非常高级的功能,主要用于框架或其他库,而不是高级程序。通常,它在像Hibernate这样的对象关系映射器中使用,用增强型替换简单的集合类,透明地获取(保存)它们在数据库中的元素。

在任何其他情况下,尝试访问类外的私有字段应被视为可能的设计缺陷的指标。 private 意味着依赖于实现,并且可以跨版本进行更改,不应该在不知道原因的情况下使用。

答案 2 :(得分:0)

最简单有效的方法是明确复制字段:

   public Destination(Source src)
   {
       this.fieldA = src.getFieldA();
       this.fieldB = src.getFieldB();
   }

我没有看到为此目的使用反射的重点。

答案 3 :(得分:0)

目前我唯一想到的就是从Destination延长Source课程

public class Source{

   private String fieldA;
   private String fieldB;

   //You need to have both Getter and Setter for fieldA and fieldB

   public Source(){ ... }
}

...

public class Destination extends Source{

   public Destination(){...}
}

Source src =  new Destination();
dest.setFieldA("test");
dest.setFieldB("test");

答案 4 :(得分:-2)

即使您将Source对象传递给Destination,也无法从Destination对象访问Source的私有成员。

您需要将字符串fieldA,fieldB添加到Destination to

string fieldA, fieldB;
public Destination(Source src)
{
   fieldA = src.fieldA;
   fieldB = src.fieldB;
}