在可变对象的getter中深度复制

时间:2016-07-15 10:29:21

标签: java oop

总是返回集合/对象字段的副本会不会有开销?

2 个答案:

答案 0 :(得分:2)

显然,是的,这将是一个开销...与返回引用或浅拷贝相比。

但这不是重点。真正的重点是开销是否合理/必要,以及是否可以通过使用其他数据结构/设计/技术来避免开销。这些问题的答案取决于具体情况。

以下是一些插图:

  1. 如果目标对象getter返回不可变对象,则不需要复制。例如,任何返回String的getter。
  2. 如果目标对象getter返回的对象不是目标对象抽象的一部分,则不希望出现副本。示例list.get(int)Iterator.next()
  3. 如果目标对象getter返回一个可变对象(或数组) AND ,则返回的对象是对象内部状态 AND 的一部分,目标不一定信任调用者,然后getter应该复制它或包装它......或者可能存在安全问题。
  4. 同样适用于非安全相关的环境;例如ArrayList.toArray(...)将列表复制到一个单独的数组中,而不是返回列表的后备数组。 (类似于getChars()StringStringBuffer等等。这就是维护抽象边界,以便课堂上不会“破坏”另一个边界。
  5. 如果目标对象getter返回一个可变对象(或数组) AND ,则返回的对象是对象内部状态 BUT 的一部分,目标对象的API /抽象边界为设计为“多孔”(例如出于性能原因),然后复制可能是自我失败。
  6. 其中,3是克隆是严格强制要求的唯一情况。在2,4和5中,您可以争辩说,这是您如何为类,库,应用程序设计公共(或内部)API的问题。通常有很多可行的选择。

答案 1 :(得分:1)

肯定是开销,但已经有一些框架类可以做到这一点。它也在Effective Java中描述。

记住:

  

"类应该是不可变的,除非有一个很好的理由使它们变得可变......如果一个类不能变成不可变的,尽可能地限制它的可变性。"

当你想创建不可变类时,你可以使用这样的框架:http://immutables.github.io

例如,请查看此Oracle documentation