发送防御性数据副本的最佳方式是什么?
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
进行防御性复制。他们这样做的原因略有不同,如下所述。
制作防御性文案有两个原因:
- 防止传入数据被修改 - 调用者向您传递一个对象,并决定稍后更改它。由于您已经制作了它的防御性副本,因此调用者所做的更改不会影响您内部存储的数据,并且
- 防止传出数据被修改 - 调用者可能会决定更改从您的方法之一接收到的对象。由于您已返回对象的防御性副本,因此您的内部数据仍然安全。
代码演示了两种情况 - OtherClass(MyData data)
构造函数演示了问题 #1,而 MyData getData()
演示了问题 #2。
请注意,仅因为决定 MyData
class mutable 才需要防御副本(即给它一个 setName
方法).无需制作 immutable classes.
对象的防御副本
我刚刚阅读了有效的 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
进行防御性复制。他们这样做的原因略有不同,如下所述。
制作防御性文案有两个原因:
- 防止传入数据被修改 - 调用者向您传递一个对象,并决定稍后更改它。由于您已经制作了它的防御性副本,因此调用者所做的更改不会影响您内部存储的数据,并且
- 防止传出数据被修改 - 调用者可能会决定更改从您的方法之一接收到的对象。由于您已返回对象的防御性副本,因此您的内部数据仍然安全。
代码演示了两种情况 - OtherClass(MyData data)
构造函数演示了问题 #1,而 MyData getData()
演示了问题 #2。
请注意,仅因为决定 MyData
class mutable 才需要防御副本(即给它一个 setName
方法).无需制作 immutable classes.