在令人惊讶的书"Java the Good Parts"中,作者给出了一些代码,这些代码在其getter方法中返回一个对象的副本(与一个封装良好的字段一起使用),然后说明:
这种方法试图返回私有数据的副本而不是对私有数据的引用,这通常是一个好主意
为什么会这样?我认为封装的目标是确保没有人能够真正改变私人成员.那我为什么要写这样的东西呢
private someType fieldName = new someType();
...
Run Code Online (Sandbox Code Playgroud)
同时定义它的getter(假设有某种复制构造函数)
someType getSomething()
{
return new someType(fieldName);
}
Run Code Online (Sandbox Code Playgroud)
从我现在所知,我的意思是在你们流行之前是:
到目前为止这是有意义的,它服务垃圾收集,因为这种方法不维护对实际对象的引用.
从内部类的角度来看,它也是可以理解的,任何方法都可以通过引用改变任何可访问的字段.
但我并不怀疑这样做的两个原因是什么才真正超越了这个问题.
Jon*_*eet 19
当类型是可变的时,返回副本通常很有用,这样客户端就不能从根本上修改数据,至少在没有告诉你的情况下.考虑:
public class Person {
private Date dateOfBirth;
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
// Do some validation, e.g. that it's after 1800
this.dateOfBirth = dateOfBirth;
}
}
Run Code Online (Sandbox Code Playgroud)
看起来没问题吧?但是关于:
Person person = new Person();
person.setDateOfBirth(new Date()); // Now... fine.
// Aha! Modify the Date to a very long time ago. Now anyone else
// using the Person will be messed up...
person.getDateOfBirth().setTime(Long.MIN_VALUE);
Run Code Online (Sandbox Code Playgroud)
如果getDateOfBirth改为返回副本,则调用者Date对返回值引用的对象所做的任何更改都将与其他任何人无关.该Person对象仍然有效,因为它只有一个有效的日期.当然,这应该被记录下来,以便编写上述代码的人会因为返回副本而不希望它影响Person对象.
一个更好的比所有这些复制的解决方案是有利于稳定的类型,但是-当你有一个不可变对象的引用,你可以共享尽可能广泛,只要你喜欢,知道没有人能在你的脚下改变其状态.
我们的想法是,getter允许您查看对象的状态而无法对其进行修改(因为您将修改副本,而不是原始副本).
如果你打电话:
someType property = someObj.getSomething();
Run Code Online (Sandbox Code Playgroud)
然后
property.setSomeSubProperty(someValue);
Run Code Online (Sandbox Code Playgroud)
这只会改变副本someType,而不是原来someType存储的副本someObj.
如果包含该getSomething()方法的类是可变的,则它可能有一个setSomething(someType value)方法,并且使用该方法将是修改该属性的可接受方法.