MaxDevelop
MaxDevelop

Reputation: 637

Why we must do defensive copying for imutable classes

why we must do Defensive Copying in order to achieve Immutable class? Look at this code:

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
    }
}

Why it won't be Immutable if we didn't do Defensive Copying?

Upvotes: 3

Views: 1723

Answers (2)

nikis
nikis

Reputation: 11234

Because otherwise it is possible to change the object state. Let's imagine, that your getDate method is the following:

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

And we use it in the following way:

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

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726619

In order to achieve immutability you must make copies of all mutable objects passed into your constructor, and also return copies for all mutable objects stored inside your class, if any.

  • If you do not make a copy of the date passed into you, the caller can change the date after your object has been constructed, effectively mutating it.
  • If you do not return a copy from a getter of a mutable object, the callers can mutate the object that they get from you, effectively mutating your object as well.

In your specific example, Date class is mutable. If yo skip copying in the constructor, malicious code can do this:

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

If you skip the second copy, the callers can do this:

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

Upvotes: 4

Related Questions