通过收集字段进行深度克隆
Deep clone by collecting the fields
我有 类 旨在包含许多不同类型的属性。我想自动深度克隆所有这些而不是为每个编写指令:
class AttributesContainer implements Cloneable {
Type1 a1 = new Type1(...), a2 = new Type1(...);
Type2 b1 = new Type2(...);
...
public AttributesContainer clone() {
AttributesContainer ac = (AttributesContainer) super.clone();
// Regroup that like using a loop
ac.a1 = a1.clone();
ac.a2 = a2.clone();
ac.b1 = b1.clone();
...
return ac;
}
}
我想过每次都在 table 中添加字段,但我无法更改字段的引用:
class ContainerAbstract implements Cloneable {
public <T> T add(T t) {
// adds the reference into a list
return t;
}
public ContainerAbstract clone() {
ContainerAbstract ca = (ContainerAbstract) super.clone();
// copy the attributes
return ca;
}
}
class AttributesContainer extends ContainerAbstract implements Cloneable {
Type1 a1 = add(new Type1(...)), a2 = add(new Type1(...));
Type2 b1 = add(new Type2(...));
...
public AttributesContainer clone() {
AttributesContainer ac = (AttributesContainer) super.clone();
return ac;
}
}
我还认为我可以 return add() 方法中的包装器,但它会引入一个额外的方法 get() 以在每次我想访问属性时调用:
AttributesContainer ac = new AttributesContainer();
ac.get()...;
有没有一种方法可以将字段更改为源,就像我们可以在 C 中使用指针实现那样?
注意:我已经检查过 Copy fields between similar classes in java, How do you make a deep copy of an object in Java? and http://www.java2s.com/Tutorial/Java/0125__Reflection/Returnalistofallfieldswhateveraccessstatusandonwhateversuperclasstheyweredefinedthatcanbefoundonthisclass.htm。
编辑:我不使用序列化的原因之一是事实上,我有一个最终的属性,我只想要一个新的实例。
我想过让它成为瞬态对象,然后给它一个新对象,但我不能,因为它是最终的:
class A {
private Double d = new Double(2);
public final transient B b = new B();
public A copy() {
A a = (A) DeepCopy.copy(this);
a.b = new B(); // Error, b is final
return a;
}
}
写文章(或问题asked/answered)时一定要检查,否则你会产生很多误解。我在评论中引用的文字位于页面底部。如果您没有看到它,请使用浏览器的 "Find in page" 功能。
序列化和反序列化final字段也不是问题。你不能这样写:a.b = new B(); // Error, b is final
,但你不需要。序列化是在 JVM 级别实现的,它可以执行很多技巧,例如在不调用任何构造函数的情况下创建对象。
最后,我找到的唯一不需要更改最终属性的答案是在 class DeepCopy 中更改 http://javatechniques.com/blog/faster-deep-copies-of-java-objects/ ObjectOutputStream 方法以替换 class 类型的属性有新的。
ObjectOutputStream out = new ObjectOutputStream(fbos) {
{
enableReplaceObject(true);
}
@Override
protected Object replaceObject(Object arg0) throws IOException {
// TODO Auto-generated method stub
if(arg0 instanceof Type) {
for(Constructor<?> constructor : arg0.getClass().getConstructors()) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
if(parameterTypes.length == 0 /* Number of arguments in the constructor of new Type(...) */)
try {
return constructor.newInstance(/* Arguments to the constructor */);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
}
try {
throw new Exception("The constructor needed to create a new Type was not found.");
} catch(Exception e) {
e.printStackTrace();
}
return null;
} else {
return super.replaceObject(arg0);
}
}
};
out.writeObject(orig);
out.flush();
out.close();
我有 类 旨在包含许多不同类型的属性。我想自动深度克隆所有这些而不是为每个编写指令:
class AttributesContainer implements Cloneable {
Type1 a1 = new Type1(...), a2 = new Type1(...);
Type2 b1 = new Type2(...);
...
public AttributesContainer clone() {
AttributesContainer ac = (AttributesContainer) super.clone();
// Regroup that like using a loop
ac.a1 = a1.clone();
ac.a2 = a2.clone();
ac.b1 = b1.clone();
...
return ac;
}
}
我想过每次都在 table 中添加字段,但我无法更改字段的引用:
class ContainerAbstract implements Cloneable {
public <T> T add(T t) {
// adds the reference into a list
return t;
}
public ContainerAbstract clone() {
ContainerAbstract ca = (ContainerAbstract) super.clone();
// copy the attributes
return ca;
}
}
class AttributesContainer extends ContainerAbstract implements Cloneable {
Type1 a1 = add(new Type1(...)), a2 = add(new Type1(...));
Type2 b1 = add(new Type2(...));
...
public AttributesContainer clone() {
AttributesContainer ac = (AttributesContainer) super.clone();
return ac;
}
}
我还认为我可以 return add() 方法中的包装器,但它会引入一个额外的方法 get() 以在每次我想访问属性时调用:
AttributesContainer ac = new AttributesContainer();
ac.get()...;
有没有一种方法可以将字段更改为源,就像我们可以在 C 中使用指针实现那样?
注意:我已经检查过 Copy fields between similar classes in java, How do you make a deep copy of an object in Java? and http://www.java2s.com/Tutorial/Java/0125__Reflection/Returnalistofallfieldswhateveraccessstatusandonwhateversuperclasstheyweredefinedthatcanbefoundonthisclass.htm。
编辑:我不使用序列化的原因之一是事实上,我有一个最终的属性,我只想要一个新的实例。
我想过让它成为瞬态对象,然后给它一个新对象,但我不能,因为它是最终的:
class A {
private Double d = new Double(2);
public final transient B b = new B();
public A copy() {
A a = (A) DeepCopy.copy(this);
a.b = new B(); // Error, b is final
return a;
}
}
写文章(或问题asked/answered)时一定要检查,否则你会产生很多误解。我在评论中引用的文字位于页面底部。如果您没有看到它,请使用浏览器的 "Find in page" 功能。
序列化和反序列化final字段也不是问题。你不能这样写:a.b = new B(); // Error, b is final
,但你不需要。序列化是在 JVM 级别实现的,它可以执行很多技巧,例如在不调用任何构造函数的情况下创建对象。
最后,我找到的唯一不需要更改最终属性的答案是在 class DeepCopy 中更改 http://javatechniques.com/blog/faster-deep-copies-of-java-objects/ ObjectOutputStream 方法以替换 class 类型的属性有新的。
ObjectOutputStream out = new ObjectOutputStream(fbos) {
{
enableReplaceObject(true);
}
@Override
protected Object replaceObject(Object arg0) throws IOException {
// TODO Auto-generated method stub
if(arg0 instanceof Type) {
for(Constructor<?> constructor : arg0.getClass().getConstructors()) {
Class<?>[] parameterTypes = constructor.getParameterTypes();
if(parameterTypes.length == 0 /* Number of arguments in the constructor of new Type(...) */)
try {
return constructor.newInstance(/* Arguments to the constructor */);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
}
try {
throw new Exception("The constructor needed to create a new Type was not found.");
} catch(Exception e) {
e.printStackTrace();
}
return null;
} else {
return super.replaceObject(arg0);
}
}
};
out.writeObject(orig);
out.flush();
out.close();