发送防御性数据副本的最佳方式是什么?

What is the best way of sending defensive copy of data ?

我刚刚阅读了有效的 java 规则 39(防御性副本)。没有明确告诉,每次数据交易都要进行两次复制才能遵循这个规则。下面是我想到的示例代码。似乎有些多余。我理解正确吗?有没有更好的方法?

public class SomeClass {

    private MyData myData; 

    SomeClass() {
        myData = new MyData("1");
    }

    public MyData getData() {
        return new MyData(myData); // 1st Copy of data
    }

    public static void main(String[] args) {
        SomeClass someClass = new SomeClass();
        OtherClass otherClass = new OtherClass(someClass.getData()); //Pass data which is invariant
    }
}

class OtherClass {

    MyData myData; 

    OtherClass(MyData data) {
        myData = new MyData(data);  // 2nd Copy of data
    }
}

class MyData {
    private String name;
    public MyData(String name) { this.name = name; }
    public MyData(MyData data) { this.name = data.name; }
    public void setName(String name) { this.name = name; }
}

你的理解是正确的,构造函数和方法都对MyData进行防御性复制。他们这样做的原因略有不同,如下所述。

制作防御性文案有两个原因:

  1. 防止传入数据被修改 - 调用者向您传递一个对象,并决定稍后更改它。由于您已经制作了它的防御性副本,因此调用者所做的更改不会影响您内部存储的数据,并且
  2. 防止传出数据被修改 - 调用者可能会决定更改从您的方法之一接收到的对象。由于您已返回对象的防御性副本,因此您的内部数据仍然安全。

代码演示了两种情况 - OtherClass(MyData data) 构造函数演示了问题 #1,而 MyData getData() 演示了问题 #2。

请注意,仅因为决定 MyData class mutable 才需要防御副本(即给它一个 setName 方法).无需制作 immutable classes.

对象的防御副本