How to define them
New Java developers may have gotten to this point in the article and started to pull their hair out. They’re asking “How would you create the object if there isn’t a constructor, and how would you define the fields if you restrict them?” Well the best way to define an immutable object is to use an Builder class, that is defined as an inner class to the object.
A builder is a class whose entire responsibility is to build one class. Typically, this is the responsibility of a constructor. However, there are situations where a constructor is not available, as with this, or multiple constructors may decrease a source file’s readability.
Finishing touches
Without application, immutable classes serve a very limited purpose. The next few sections will explain how to use immutable objects with various other frameworks/libraries. A beginner may immediately jump to suggest adding the keyword final will solve the problem with immutability. This is incorrect, and depending on where the keyword is, incorrect.
If the final keyword is appended to the class declaration, the class may not be extended. If the keyword is on an instance variable the reference may not be changed after once being declared. If the instance variable is a primitive data type, then the value cannot be changed after the object is constructed. However, if the type is an object, then the content within the reference may be modified [if the object allows mutable access]. If the final keyword is before the return type of a method, the method cannot be overridden by an extending class. If the final keyword is before a parameter, means that the reference may not be changed within the method.
For example, a class that exposes the reference to a Date field of the class may be modified outside of the class by using the reference’s setters. The date object’s main storage of data is based on a long variable. To prevent this from causing an issue in your custom types, non-primitive accessor methods should clone the reference before returning.
An example of this can be seen here:
Main Method:
public static void main(String[] args) {
ImmutableClassicl = new ImmutableClass();
MutableClass mcl = new MutableClass();
Date immutableVar = icl.getToday();
Date mutableVar = mcl.getToday();
//Lets do something destructive
immutableVar.setTime(0);
mutableVar.setTime(0);
DateFormatd form = new SimpleDateFormat();
System.out.println("The Immutable Class returns: "+ dform.format(icl.getToday()));
System.out.println("The Mutable Class returns: "+ dform.format(mcl.getToday()));
}
The MutableClass:
public class MutableClass {
private Date today = new Date();
public Date getToday() {
return today;
}
}
The ImmutableClass:
public class ImmutableClass {
private Date today = new Date();
public Date getToday() {
return new Date(today.getTime());
}
}
Please note, there are no modifiers provided in both of the Immutable/Mutable classes. Without modifier methods, the developer should assume that the internal state is not accessible to be modified from the outside world. However, as one would expect this behaves a bit differently. The result of the main method is:
The Immutable Class returns: 10/9/11 9:07 PM
The Mutable Class returns: 12/31/69 7:00 PM