Monday 17 February 2014

How to create Immutable objects in Java

We can divide objects broadly as mutable and immutable objects.

Mutable Objects:

Mutable objects are those objects whose contents can be modified. Means if you have reference of an object, contents of the object can be altered. For example:--

If we have a Person class with firstName, lastName fields and corresponding getter and setter methods and  constructor. Then we can create an instance as :

Person p = new Person("Baljeet", "Singh");  //Created a person object with first name and last name

Now we can alter the contents of instance p of Person class as below
p.setFirstName("XYZ"); //Here we have altered the p instance of class Person and first name is now set to "XYZ" insteab of  "Baljeet"

Immutable Objects:

Immutable objects are those objects, once created can not be modified. Means even if you have reference to an object, contents of that object can't be modified or altered. String objects are immutable.

For example :--

String s = "abcd"; //a new String object is created with value "abcd" on string pool in heap. See below diagram:



Now lets do concat operation string object s which we created earlier.
s = s + "ef"; // Here on doing contact operation, a new object reference is returned with value "abcdef "and reference is assigned to s. Now s holds a reference to a new String object in String pool whose value is "abcdef" and earlier String literal is still present in String pool.

 See below diagram for more clarification.



This means String objects are immutable means when ever you do any manipulation with Strings, result of that operation will always be a new String object. 

Steps to achieve immutability in Java:

1. Make all the fields of the class as private and final.
    
Make the fields private so that fields are not accessible directly and hence can't be modified if there are no setters for those fields. Fields are marked as final so that fields can't be modified even through reflection in Java.  

2. Don't provide setters for class fields.

Don't  provide any public method that can any how modify the fields.

3.  Make sure methods of a class can't be overridden.

To protect fields from modification, make sure methods of class are not overridden. This is because child class can override some method behavior and update some of the fields of the parent class. So either make class itself as final or make each method of class as final so that methods can't be overridden.

4.  Build your class from primitive types or immutable fields.
Try to use immutable fields such as Strings or primitive types in your class. If any of class field includes  references any mutable object, don't allow those objects to be changed by following below approaches :--

1. Don't provide methods that modify the mutable objects. Means don't even provide getter for that field because if you provide any getter, which returns the reference to the mutable object and object can be modified.

2. 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.


See below class to create immutable object.

import java.util.Date;

public final class  Person {
 
    //Fields are marked as private and Final
  
    final private String firstName;
  
    final private String lastName;
  
    final private Date dob;
  
  
    //public constructor to set the values while creating instance of the class
    public Person(String firstName, String lastName, Date dob)
    {
        this.firstName =  firstName;
        this.lastName = lastName;
        this.dob = dob;
    }

  
    //getters only for immutable fields only. No setters at all
    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

 /*As dob is of type Date, which holds the reference to a Date object. If we provide getters for dob field,  which will return the reference to Date instance, through which Person class instance can be altered. Hence even getter for dob is commented out.  
*/
  
/*public Date getDob() {
        return dob;
 }*/
  
}




   
 





No comments:

Post a Comment