Do fields need to be explicitly final to have a "proper" immutable object?
You often read about immutable objects requiring final fields to be immutable in Java. Is this in fact the case, or is it simply enough to have no public mutability and not actually mutate the state?
For example, if you have an immutable object built by the builder pattern, you could do it by having the builder assign开发者_StackOverflow the individual fields as it builds, or having the builder hold the fields itself and ultimately return the immutable object by passing the values to its (private) constructor.
Having the fields final has the obvious advantage of preventing implementation errors (such as allowing code to retain a reference to the builder and "building" the object multiple times while in fact mutating an existing object), but having the Builder store its data inside the object as it is built would seem to be DRYer.
So the question is: Assuming the Builder does not leak the Object early and stops itself from modifying the object once built (say by setting its reference to the object as null) is there actually anything gained (such as improved thread safety) in the "immutability" of the object if the object's fields were made final instead?
Yes, you do get "thread safety" from final
fields. That is, the value assigned to a final
field during construction is guaranteed to be visible to all threads. The other alternative for thread safety is to declare the fields volatile
, but then you are incurring a high overhead with every read… and confusing anyone who looks at your class and wonders why the fields of this "immutable" class are marked "volatile."
Marking the fields final
is the most correct technically, and conveys your intent most clearly. Unfortunately, it does make the builder pattern very cumbersome. I think it should be possible to create an annotation processor to synthesize a builder for an immutable class, much like Project Lombok does with setters and getters. The real work would be the IDE support needed so that you could code against the builders that don't really exist.
An Object can certainly have mutable private fields and still work as an immutable object. All that matters to meet the contract of immutability is that the object appears immutable from the outside. An object with non-final private fields but no setters would for example satisfy this requirement.
In fact, if your encapsulation is right then you can actually mutate the internal state and still operate successfully as an "immutable" object. An example might be some sort of lazy evaluation or caching of data structures.
Clojure for example does this in its internal implementation of lazy sequences, these objects behave as if they are immutable but only actually calculate and store future values when they are directly requested. Any subsequent request retrieves the stored value.
However - I would add as a caveat that the number of places where you would actually want to mutate the internals of an immutable object are probably quite rare. If in doubt, make them final.
I think you would just need to consider the environment its running in and decide if frameworks that use reflection to manipulate objects are a hazard.
One could easily cook up an oddball scenario where a supposedly immutable object gets clobbered via a POST injection attack because of a web binding framework that's configured to use reflection instead of bean setters.
You definitely can have an immutable object with non-final fields.
For example see java 1.6 implementation of java.lang.String.
Comment: @erickson
Like that:
class X { volatile int i, j; } X y; // thread A: X x = new X; x.i = 1; x.j = 2; y = x; // thread B: if (y != null) { a = y.i; b = y.j; }
?
精彩评论