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

时间:2018-01-06 14:26:13

标签: java effective-java defensive-programming

我刚读过有效的java规则39(Defensive Copy)。没有明确说明,每次数据事务都应遵循此规则进行两次复制。下面是我想到的示例代码。这似乎有点多余。我理解正确吗?还有更好的办法吗?

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; }
}

1 个答案:

答案 0 :(得分:1)

您的理解是正确的,构造函数和方法都会制作MyData的防御性副本。他们这样做的原因略有不同,如下所述。

制作防御性副本有两个原因:

  1. 防止对传入数据的修改 - 调用者会向您传递一个对象,并决定稍后更改它。由于您已对其进行了防御性复制,因此调用者所做的更改不会对您在内部存储的数据产生任何影响,并且
  2. 防止传出数据的修改 - 调用者可能决定更改从您的某个方法接收的对象。由于您已经返回了对象的防御副本,因此您的内部数据仍然安全。
  3. 代码演示了这两种情况 - OtherClass(MyData data)构造函数演示了问题#1,而MyData getData()演示了问题#2。

    请注意,只有因为决定MyData可变(即给它setName方法)才需要防御性副本。没有必要制作不可变类对象的防御性副本。