为什么在不可变类中的getter中制作防御性副本?

ioz*_*zee 17 java

这个问题是关于良好的编程实践和避免潜在的漏洞.
我读了Joshua Bloch的Effective Java,这就是我想知道的:
为什么我要考虑在我的不可变类中使用getter方法制作防御性副本而不使用mutator?
第二:除了私人之外,我为什么要让我的领域最终成绩?这只是关于性能(不是安全性)吗?

Tom*_*icz 39

我相信这是证明这一陈述的理由:

public class Immutable {

    private final String name;

    private Date dateOfBirth;

    public Immutable(String name, Date dateOfBirth) {
        this.name = name;
        this.dateOfBirth = dateOfBirth;
    }

    public String getName() {
        return name;
    }

    public Date getDateOfBirth() {
        return dateOfBirth;
    }

}
Run Code Online (Sandbox Code Playgroud)

getName()很好,因为它也返回不可变对象.但是,该getDateOfBirth()方法可能会破坏不变性,因为客户端代码可以修改返回的对象,因此也可以修改对象Immutable:

Immutable imm = new Immutable("John", new Date());

imm.getName(); //safe
Date dateOfBirth = imm.getDateOfBirth();
//hundreds of lines later
dateOfBirth.setTime(0);  //we just modified `imm` object
Run Code Online (Sandbox Code Playgroud)

返回不可变对象和基元是安全的(因为它们是按值返回的).但是,您需要制作可变对象的防御性副本,例如Date:

public Date getDateOfBirth() {
    return new Date(dateOfBirth.getTime());
}
Run Code Online (Sandbox Code Playgroud)

并将集合包装在不可变的视图中(如果它们是可变的),例如Collections.unmodifiableList():

public List<Integer> getSomeIds() {
    return Collections.unmodifiableList(someIds);
}
Run Code Online (Sandbox Code Playgroud)