在Java中,我有一个方法,可以根据对象from
的相应属性修改对象to
的属性。
public static void shape(SomeType from, SomeType to) {
to.setA( from.getA() );
to.setB( from.getB() );
to.setC( from.getC() );
...
}
我可以想象这个任务/习语在软件开发中经常出现,以至于它既被赋予了一个名字,又有现有的库可以自动为我完成它。你知道任何这样的库吗?
我不想要这样的库。您的对象最终可能会出现许多意外状态。正如其他人所说,使用复制构造函数。
一般来说,如果你能负担得起,在转换状态时争取不变性。它通常使对问题的推理更容易,并降低副作用的风险。一个很好的例子是joda time,它大量使用不变性。
方法是使用复制构造函数或复制方法。
public SomeType(SomeType other)
{
a = other.a;
b = other.b;
c = other.c;
}
public void copy(SomeType other)
{
a = other.a;
b = other.b;
c = other.c;
}
我不确定是否有人会在实践中真正做到这一点,但理论上你可以使用反射来自动化这个过程(getMethods 可能是一个好的开始)。除了可能的性能问题(不知道这有多快)之外,我想到的主要问题是这可能会导致您不希望复制的数据被复制,当多人处理同一代码时尤其可能发生。
我认为没有通用的解决方案。也许AOP可以提供帮助,但这可能是一种不好的做法。
如果你想复制对象的所有数据并且它们属于同一个类,那么该类的实现者可以实现可克隆接口,你可以只调用clone()。
如果类不同,那么只有您知道应该将源对象的哪些成员复制到目标对象的哪些成员。一个接一个地复制它们是执行此操作的最简单,最易读的方法。
还有一个成员的"浅"或"深"复制的问题,超出了问题的范围,但值得记住。
这已经准备好了,在这里问贝福德。查看 通过反射将所有值从一个类中的字段复制到另一个类 。
我用过推土机 - 但又回到了@dukeling提到的使用复制构造函数。
尝试实现可克隆接口
public class SomeType implements Cloneable {
private String a;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public Object clone() {
try {
return super.clone();
} catch(CloneNotSupportedException e) {
System.out.println("Cloning not allowed.");
return this;
}
}
}
你可以测试这个:
public class Test {
public static void main (String args[]) {
SomeType a = new SomeType();
SomeType b = (SomeType) a.clone();
if ( a == b ) {
System.out.println( "yes" );
} else {
System.out.println( "no" );
}
}
}
是的,如果对象类型不同,您可以尝试使用反射,但请记住,属性的名称必须相等
这就是使用反射的答案,使用此类,只要方法和属性的名称相同,您就可以将所有参数从一个对象传递到另一个对象,无论类型如何。
package co.com;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class SetAttributes {
public static String capitalize( String word ) {
return Character.toUpperCase( word.charAt( 0 ) ) + word.substring( 1 );
}
public static void setAttributes( Object from, Object to ) {
Field [] fieldsFrom = from.getClass().getDeclaredFields();
Field [] fielsdTo = to.getClass().getDeclaredFields();
for (Field fieldFrom: fieldsFrom) {
for (Field fieldTo: fielsdTo) {
if ( fieldFrom.getName().equals( fieldTo.getName() ) ) {
try {
Method [] methodsTo = to.getClass().getDeclaredMethods();
for ( Method methodTo: methodsTo ) {
if ( methodTo.getName().equals( "set" + capitalize( capitalize( fieldTo.getName() ) ) ) ) {
Method methodFrom = from.getClass().getDeclaredMethod( "get" + capitalize( fieldFrom.getName() ), null );
methodTo.invoke(to, methodFrom.invoke( from, null ) );
break;
}
}
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
System.err.println( fieldFrom );
}
}
}
public static void main (String args[]) {
SomeType a = new SomeType();
SomeType b = new SomeType();
a.setA( "This" );
setAttributes( a, b );
System.err.println( b.getA() );
}
}