【问题标题】:How do I make defensive copy of an object?如何制作对象的防御性副本?
【发布时间】:2011-02-26 15:24:02
【问题描述】:

如何制作包含不可变对象中的可变字段的可变对象的防御性副本?

class ImmutableObject {

  private final MutableObject immutable_field;

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

class MutableObject {

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

【问题讨论】:

  • 抱歉我的无知,但什么是对象的“防御性副本”?有哪些用例?
  • 如果它包含一个可变对象,它就不是真正的不可变,是吗?...您不会拥有不可变对象附带的安全性和并发性。
  • @kunjaan:封装了可变对象的对象,无论如何都不是“不可变的”。您对 Artefacto 的评论完全是虚假的:这并不是因为存在称为 “防御性复制” 的技术,因此使用它会自动使您的对象“不可变”。将主类命名为 ImmutableObject 很愚蠢:如果它包含可变对象,防御性副本或否,那么您的类就不是不可变的
  • @kunjaan:我对不可变的定义和 Artefacto 一样,也和其他人一样。您可能是唯一一个认为由于您的字段无法更改的人,即使它包含一个可变对象,它仍然是一个不可变对象。你的定义既错误又是垃圾。
  • 无需敌对。我试图将一个可变对象封装成一个不可变对象。我将所有内容都精简到最低限度,并更改了类的名称以表明它们中的哪些需要是不可变的。我只是在这里学习。请更换你的垫子。

标签: java defensive-copy effective-java


【解决方案1】:

好吧,假设对可变对象类的声明没有什么可做的,可以利用反射(Class.newIntance()Class.getFields())创建一个新对象并复制字段值。您也可以通过这种方式实现深度复制。如果该类支持序列化,那么另一种骇人听闻的方法是序列化对象,然后保存反序列化的副本。但是,如果可以修复可变对象的设计,那将是更好的方法。

编辑
对于您给出的特定示例,Romain 的答案可以满足您的要求。如果你有一个通用的可变对象,它不提供复制它的机制,并且它的类型可能直到以后才知道,那么反射方法就是实现复制机制的方式。

【讨论】:

  • 谢谢,这涵盖了问题的另一部分。 +1
【解决方案2】:

你需要做的是在

  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

【讨论】:

  • 问题不在返回时,而是在构建时。
  • @OP:不管怎样,基本都一样。
猜你喜欢
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-09
  • 1970-01-01
  • 2013-10-12
  • 1970-01-01
相关资源
最近更新 更多