Java防御性复制和不可变

时间:2015-04-01 08:39:04

标签: java immutability copying

为什么我们必须做防御性复制才能实现Immutable类? 看看这段代码:

public final class EmailMessage   {
    private final String from;
    private final String to;
    private final String message;
    private final Date   date;

    public EmailMessage( String from, String to, String msg, Date date )
    {
        this.to = to;
        this.from = from;
        this.message = msg;
        this.date = new Date(date.getTime());// instead of date;
    }

    public String getFrom()
    {
        return( from );
    }

    public Date getDate() {
        return( new Date( date.getTime() ); // instead of Date
    }
}

如果我们不进行防御性复制,为什么它不会是不可变的?

2 个答案:

答案 0 :(得分:2)

为了实现不变性,您必须复制传递给构造函数的所有可变对象,并返回存储在类中的所有可变对象的副本(如果有)。

  • 如果您没有复制传递给您的日期,则调用者可以在构建对象后更改日期,从而有效地改变它。
  • 如果您没有从可变对象的getter返回副本,则调用者可以改变他们从您那里获得的对象,从而有效地改变您的对象。

在您的具体示例中,Date类是可变的。如果你在构造函数中跳过复制,恶意代码可以这样做:

Date d = new ...
EmailMessage msg = new EmailMessage("lazy dog", "quick brown fox", "Jump!", d);
d.setTime(d.getTime()+12345); // Changes the date inside msg

如果您跳过第二个副本,则呼叫者可以执行此操作:

EmailMessage msg = ...
Date d = msg.getDate();
d.setTime(d.getTime()+12345); // Changes the date inside msg

答案 1 :(得分:2)

因为否则可以改变对象状态。我们假设您的getDate方法如下:

public Date getDate() {
    return date; // instead of Date
}

我们以下列方式使用它:

EmailMessage msg = new EmailMessage(...); // initialization
Date date = msg.getDate();
date.setTime(...); //ooops, our msg object has another date now