我想知道以下情况是否可行。
有两个类(源和目标),在代码中我可以这样做:
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中实现吗?如果可能的话,有人可以给我一个我可以开始的小例子。
答案 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 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;
}