Could you please clarify that why final keyword is required before class when we are making it an immutable one. I mean, if we declare all of it's attributes as private and final, then also it is an immutable class, isn't it?
Sorry if the question seems easy, but i am truly confused about it. Help me out.
Editted: I know that a class declared final can't be subclassed.. But if each attribute is private and final then what difference does that make?
If an immutable class
Foo
is sealed ("final"), then anyone who receives a reference to aFoo
may be assured that ifFoo
was implemented correctly, the referenced instance will in fact be immutable. If an immutable class is not sealed, then someone who receives a reference to aFoo
may be assured that if the actual class of of the referenced object (which may beFoo
or some derivative type implemented by some arbitrary unknown person) was implemented correctly, the instance will be immutable. LeavingFoo
unsealed means that anyone who relies uponFoo
to be immutable will have to trust that everyone who writes a class that derives fromFoo
will implement it correctly. If one wants to be certain that every reference to aFoo
will in fact target an immutable instance without having to rely upon the authors of derivative classes to abide by the contract, makingFoo
final can aid in such assurance.On the other hand, the possibility that a class might derive from
Foo
but violate its immutability isn't terribly different from the possibility that a class which derives from any other class might violate the contracts of its parent class. Any code which accepts a reference of any type which can be subclasssed by outside code might be given an instance of a subclass which violates its parent's contract.The fundamental question when deciding whether an immutable class should be sealed is the same as for any other class: whether the benefits of leaving the type unsealed outweigh any dangers that would be posed by doing so. In some cases, it may make sense to have an extensible immutable class, or even an abstract class or interface whose concrete implementations are all contractually obligated to be immutable; for example, a drawing package might have an
ImmutableShape
class with some concrete fields, properties, and methods to define 2D transformations, but an abstractDraw
method, allowing for the definition of derivative typesImmutablePolygon
,ImmutableTextObject
,ImmutableBezierCurve
, etc. If someone implements anImmutableGradientFilledEllipse
class but fails to have that type make its own copy of a mutableGradientColorSelector
, the colors of gradient-filled polygons might change unexpectedly, but that would be a fault of theImmutableGradientFilledEllipse
class, and not the consuming code. Despite the possibility of a broken implementation failing to uphold the "immutability" contract, an extensibleImmutableShape
class would be much more versatile than a sealed one.An immutable object is an object which state is guaranteed to stay identical over its entire lifetime. While it is perfectly possible to implement immutability without final, its use makes that purpose explicit, to the human (the software developer) and the machine (the compiler).
Immutable objects carry some very desirable characteristics:
Clearly final is going to help us define immutable objects. First in labelling our object as immutable, which makes it simple to use and understand by other programmers. Second in guaranteeing that the object's state never changes, which enable the thread-safe property: thread concurrency issues are relevant when one thread can change data while another thread is reading the same data. Because an immutable object never changes its data, synchronizing access to it is not needed.
Create an immutable class by meeting all of the following conditions:
A class declared final cannot be sub classed. Other classes cannot extend final class. It provides some benefit to security and thread safety.
A class that is declared final cannot be subclassed. See also http://docs.oracle.com/javase/tutorial/java/IandI/final.html
The different semantics of all uses of the final keyword are described in the The Java Language Specification
As stacker says,
final
makes sure the class isn't subclassed. That's important so that any code which is relying on its immutability can do so safely.For example, immutable types (where each field is also of an immutable type) can be freely used between threads without worrying about data races etc. Now consider:
That looks like you can share
Person
instances freely across threads with no problem. But what about when the object you're sharing is actually a mutable subclass:Now instances of
Employee
aren't safe to share between threads, because they're not immutable. But the code doing the sharing may only know about them as instances ofPerson
... leading them into a false sense of security.The same goes for caching - it should be safe to cache and reuse immutable types, right? Well, it is safe to cache instances which are genuinely of an immutable type - but if you're dealing with a type which itself doesn't allow mutation, but does allow subclasses, it's suddenly not safe any more.
Think about
java.lang.Object
. It doesn't have any mutable fields, but it's clearly a bad idea to treat everyObject
reference as if it's a reference to an immutable type. Basically it depends on whether you think about immutability as a property of the type or of objects. A truly immutable type declares "any time you see a reference of this type, you can treat it as immutable" - whereas a type which allows arbitrary subclassing can't make that claim.As an aside, there's a half-way house: if you can limit the subclassing to only "trusted" places, you can ensure that everything's immutable, but still allow that subclassing. The access in Java makes that tricky, but in C# for example you could have a public class which only allowed subclassing within the same assembly - giving a public API which is nice and strong in terms of immutability, while still allowing for the benefits of polymorphism.
If all public and protected methods are final and none of them allows modifying private fields, and all public and protected fields are both final and immutable, then I guess it could be said class is semi-immutable, or sort of constant.
But things break down when you create a subclass and need to override equals and hashcode. And can not because you made them final... So the whole thing is broken, so just make the whole class final to prevent programmer from being a fool by accident.
As an alternative to doing this kind of bastardized version immutability, you have several options.
If you want to attach extra data to immutable instance, use
Map
. Like if you wanted to add age to name, you would not doclass NameAge extends String
... :-)If you want to add methods, create a class of static utility functions. That is a bit klunky, but it is the current Java way, Apache commons for example is full of such classes.
If you want to add extra methods and data, create a wrapper class with delegate methods to methods of the immutable class. Anybody needing to use the extra methods needs to be aware of them anyway, and there is not much practical difference in casting to derived non-immutable class or doing something like
new MyWrapper(myImmutableObj)
for many use cases.When you really have to have reference to original imutable object (like storing it in existing class you can not change), but need the extra data somewhere, you need to use the
Map
approach to keep the extra data around, or something like that.You don't strictly need final to make an immutable class. i.e. you can make an immutable class without it being final.
However, if you don't make it final, then it is possible for someone to extend a class and create a subclass that is mutable (either by adding new mutable fields, or overriding methods in a way that enables you to mutate protected fields of the original immutable class). This is a potential problem - it violates the Liskov Substitution Principle, in the sense that you would expect the property of immutablity to be preserved by all subtypes.
Hence, it is usually good practice to make immutable classes final to avoid this risk.