How can we maintain Immutability of a class with a mutable reference

Well, the concept is reading the JLS and understanding it. Chapter 17 of the JLS "Threads and Locks" describes memory visibility and synchronization. Section 17.5 "Final Field Semantics" describes the memory visibility semantics for final fields. That section says in part:

final fields also allow programmers to implement thread-safe immutable objects without synchronization. A thread-safe immutable object is seen as immutable by all threads, even if a data race is used to pass references to the immutable object between threads. This can provide safety guarantees against misuse of an immutable class by incorrect or malicious code. final fields must be used correctly to provide a guarantee of immutability.

The usage model for final fields is a simple one: Set the final fields for an object in that object's constructor; and do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are.

So you need to:

  1. Make address both final and private.
  2. For any mutable object, you must prevent the reference to that object from being seen externally.

In this case, #2 probably means you can't return a reference to Address like you have with getAddress(). And you have to make a defensive copy in the constructor. I.e., make a copy of any mutable parameter, and store the copy in Employee. If you can't make a defensive copy, there's really no way to make Employee immutable.

public final class Employee{
    private final int id;
    private final Address address;
    public Employee(int id, Address address)
    {
        this.id = id;
        this.address=new Address();  // defensive copy
        this.address.setStreet( address.getStreet() );
    }
    public int getId(){
        return id;
    }
    public Address getAddress() {
        Address nuAdd = new Address(); // must copy here too
        nuAdd.setStreet( address.getStreet() );
        return nuAdd;
}

Implementing clone() or something similar (a copy ctor) would make creating defensive objects easier for complicated classes. However, the best recommendation I think would be to make Address immutable. Once you do that you can freely pass around its reference without any thread-safety issues.

In this example, notice I do NOT have to copy the value of street. Street is a String, and strings are immutable. If street consisted of mutable fields (integer street number for example) then I would have to make a copy of street also, and so on ad infinitum. This is why immutable objects are so valuable, they break the "infinite copy" chain.

Since this question is getting popular, I should also add a mention of Brian Goetz's book, Java Concurrency in Practice, which is how I learned about these techniques, and I'm basically paraphrasing that book above.


Well there is steps provided by Java docs

A Strategy for Defining Immutable Objects

The following rules define a simple strategy for creating immutable objects. Not all classes documented as "immutable" follow these rules. This does not necessarily mean the creators of these classes were sloppy — they may have good reason for believing that instances of their classes never change after construction. However, such strategies require sophisticated analysis and are not for beginners.

  • Don't provide "setter" methods — methods that modify fields or objects referred to by fields.
  • Make all fields final and private.
  • Don't allow subclasses to override methods. The simplest way to do this is to declare the class as final. A more sophisticated approach is to make the constructor private and construct instances in factory methods.
  • If the instance fields include references to mutable objects, don't allow those objects to be changed:
    • Don't provide methods that modify the mutable objects.
    • Don't share references to the mutable objects. Never store references to external, mutable objects passed to the constructor; if necessary, create copies, and store references to the copies. Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods.

Address class is mutable because you can modify it with the setStreet method. So other class can modify this class.

We can defend against this by taking a copy of the of the Address instance when it is passed in rather than trusting the reference to the instance we are given.

Making Address object final

private final Address address;

Secondly,

this.address = new Address(address.getStreet());

Create constructor in Address class that sets Street.Remove setter method for street.

And finally instead of

public Address getAddress(){
    return address;
} 

Use

public Address getAddress(){
    return new Address(address.getStreet());
}

If you want to encapsulate a mutable object into an immutable one, then you need to:

  1. Create a copy of the mutable object (i.e. via copy constructor, cloning, serialization/deserialization, etc.); never store the reference to the original mutable object.
  2. Never return the mutable object. If you must to, then return a copy of the object.
  3. Avoid methods which can change the mutable object.

public Employee(int id, Address address){

        this.id = id;
        this.address=new Address();  
        this.address.setStreet( address.getStreet() );
    }



public Address getAddress() {
        Address nuAdd = new Address(); // must copy here too
        nuAdd.setStreet( address.getStreet() );
        return nuAdd;
}