A classic example of an immutable object is an instance of the Java String class.
String s = "ABC";
s.toLowerCase();
The method toLowerCase() will not change the data "ABC" that s contains. Instead, a new String object is instantiated and given the data "abc" during its construction. A reference to this String object is returned by thetoLowerCase() method. To make the String s contain the data "abc", a different approach is needed.
s = s.toLowerCase();
Now the String s references a new String object that contains "abc". There is nothing in the syntax of the declaration of the class String that enforces it as immutable; rather, none of the String class's methods ever affect the data that a String object contains, thus making it immutable.
By default, fields and local variables are mutable. They can be made immutable using the final keyword.
int i = 42;
i = 43; // OK
final int j = 42;
j = 43; // does not compile
Primitive wrappers (Integer, Long, Short, Double, Float, Character, Byte, Boolean) are also all immutable. Immutable classes can be implemented by following a few simple guidelines
· 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.