To make a class truly immmutable, all members of the class must be immutable and the class itself must be final
. This ensures the object cannot be changed from within the class or outside of the class.
To make members inside the class immutable, this means more than just making them final
. For example
private final List<String> strings = new LinkedList<String>();
strings
is final
but can still be changed because items can be added and removed from the list. In this case, you could wrap it in an unmodifiable collection. Even this is not perfect though because the objects in your list could be mutable (Strings
are not obviously, but your list might have mutable objects in them where you could do list.get(index).mutator(...)
)
There is no silver bullet as to how to make an object immutable. If it provides any methods that mutate the object, then it cannot be immutable.
As for making a class final
, to achieve guaranteed immutability this necessary. Imagine the case,
class MyImmutableClass {
private final String name
}
class MutableClass extends MyImmutableClass {
private String mutableValue;
public void setMutableValue(String mutableValue...)
}
void doSomething(MyImmutableClass c) {...}
There is no guarantee that doSomething
is actually dealing with an immutable instance but rather it could be dealing with a mutable subclass. As you can see, this would pose a problem for working with interfaces. There is no way to guarantee that an implementor of an interface is immutable.
The @Immutable
annotation does not guarantee immutability, but rather just states that the class is telling you it is immutable, but there is no good way to enforce that.
If you are able to work in groovy the @Immutable
annotation has some effect as it does a lot of these techniques above that I mentioned. http://groovy.codehaus.org/Immutable+AST+Macro