“假设您正在向/从方法传递或返回对可变对象的引用数组。仅制作引用副本是否安全?制作浅拷贝是否安全?”
这是我班上的一个学习问题,答案是“两者都不安全。在这种情况下,只有深拷贝是安全的。”
为什么是这样?
“安全”可能意味着很多事情,但在您的特定上下文中,它是关于“您的”私有数据的安全性(文本将“您”称为某些 Java 类的作者)。如果您让您的班级的客户在您背后访问和修改它,您的私人数据就不会是安全的。
所以:
如果返回一个可变对象数组,则必须复制所有这些对象并将它们返回到一个新数组中;
如果你得到一个传入的可变对象数组,你必须再次将它们全部复制并放入一个新数组中——因为你的客户端已经引用了他传入的对象。
在实践中,所有这些都是大量的 CPU 工作并占用内存,因此很少这样做。您要么将所有内容设计为不可变,要么忍受可变对象固有的危险。
如果您的对象是可变的,则意味着任何引用它们的客户端都可以修改它们。这可能导致竞争条件、死锁和其他不好玩的行为。但是,如果您在使用对象之前制作对象的深层副本,您将有效地使用对象的快照。这确保没有其他客户端能够修改它们,从而消除了任何并发性或正确性问题。
在第一种情况下,原始数组元素和对象都可以修改。在第二种情况下,只能修改对象,因为我们不再可以访问原始数组。如果您执行深度复制,我们将使用完全不同的数组和对象,所以它当然是安全的。