【问题标题】:What is the best way of sending defensive copy of data ?发送防御性数据副本的最佳方式是什么?
【发布时间】:2018-01-06 14:26:13
【问题描述】:

我刚刚阅读了有效的 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; }
}

【问题讨论】:

  • 更好的方法是通过使用不可变类来避免防御性副本。我很确定这本书会谈到这一点。
  • 注意:并非所有类都有复制构造函数

标签: java effective-java defensive-programming


【解决方案1】:

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

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

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

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

请注意,防御性副本是必需的,只是因为决定使MyData可变(即给它一个setName 方法)。无需为不可变类的对象制作防御性副本。

【讨论】:

    猜你喜欢
    • 2011-01-15
    • 1970-01-01
    • 2016-05-22
    • 1970-01-01
    • 2011-04-27
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    相关资源
    最近更新 更多