如何制作对象的防御性副本?

3

如何在不可变对象中保护包含可变字段的可变对象的副本?

class ImmutableObject {

  private final MutableObject immutable_field;

  ImmutableObject(MutableObject y) {
    this.immutable_field = y;
  }
}

class MutableObject {

  public int mutable_field;
}
  • MutableObject没有一个可以让我设置字段的构造函数。
  • MutableObject的当前状态应该被捕获在Immutable Object中,并且永远不能改变。

1
抱歉我的无知,什么是对象的“防御性拷贝”?有哪些使用情况? - Xavier Ho
2
如果包含可变对象,那么它就不是真正的不可变了,对吧?您将无法获得与不可变对象相关的安全性和并发性好处。 - Artefacto
2
@kunjaan:封装可变对象的对象绝不是“不可变”的,你对Artefacto的评论完全是无稽之谈:并不是因为存在一种叫做“防御性复制”的技术,使用它就会自动使你的对象“不可变”。给你的主类命名为ImmutableObject是愚蠢的:如果它包含一个可变对象,无论是否进行了防御性复制,你的类都不是不可变的 - NoozNooz42
1
@kunjaan:我的不可变定义与Artefacto和其他人相同。你可能是唯一一个认为,即使包含可变对象,因为你的字段不能被更改,它仍然是一个不可变对象。你的定义既错误又无意义。 - NoozNooz42
1
不要生气。我试图将一个可变对象封装成一个不可变对象。我将所有东西都简化到最基本的程度,并更改了类的名称以表示哪些类需要是不可变的。我只是在学习这个。请换一下你的笔记本。 - unj2
显示剩余5条评论
2个回答

7

你需要做的是在

  MutableObject return_immutable_field() {
    return immutable_field;
  }

更改为:

  MutableObject return_immutable_field() {
    MutableObject tmp = new MutableObject();
    tmp.mutable_field = immutable_field.mutable_field;
    return tmp;
  }

这里有一个解释,请查看 http://www.javapractices.com/topic/TopicAction.do?Id=15


问题不在返回时,而是在构建时。 - unj2
1
@OP:无论如何,基本上都是一样的。 - Thomas Eding

4
假设不能改变可变对象类的声明,可以利用反射(Class.newIntance()Class.getFields())创建一个新对象并拷贝字段值。也可以通过这种方式实现深层复制。如果该类支持序列化,则另一种hackish方法是将对象序列化,然后保存反序列化副本。但是,如果可能修复可变对象的设计,那将是更好的方法。
编辑 针对您给出的特定示例,Romain的答案可以满足您的需求。如果有一个通用的可变对象,它没有提供复制机制,并且类型可能不会在以后知道,则反射方法是实现复制机制的方法。

谢谢,这回答了问题的另一部分。+1 - Romain Hippeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接