Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best design approach for creating Immutable Class

I am reading about the specific guidelines that needs to be followed while creating Immutable Class in Effective Java.

I read that In Immutable class method should not allowed to be overridden otherwise overridden method may change the behaviour of method. Following are the design approaches available in java to solve this problem :-

  1. We can mark class final but as per my understanding, it has a one disadvantage that it makes the class inextensible.

  2. Secondly is to make individual methods final but I can not get other disadvantage besides that we need to individually mark each method as final in order to prevent overridding.

  3. As per book,better approach is to make the constructor private or package-private and provide public static factory method for creating object.

My question is: Even if we include private or default constructor in the class, it cannot be extended anymore in same package (in other package in case of package-private constructor), it has a same problem which the first one had. How is it considered as the better approach than the previous ones?

like image 748
Vinit89 Avatar asked May 02 '26 14:05

Vinit89


1 Answers

An immutable object should not be extensible. Why?

Because extending it will allow either direct access to fields (if they are protected which would allow writing methods that change them), or adding state which may be mutable.

Imagine we wrote a class FlexiblyRoundableDouble that extends Double, which has an additional field roundingMode that lets us choose a "rounding mode". You could write a setter for this field, and now your object is mutable.

You can argue that if all the methods are set as final, you cannot change the original behavior of the object. The only methods that could access your roundingMode field are new methods that are not polymorphically available if you assign your object to a Double variable. But when a class's contract says that it's immutable, you make decisions based on that. For example, if you write a clone() method or copy constructor for a class that has Double fields, you know that you don't need to deep-copy the Double fields, as they do not change their state, and can therefore be safely shared between the two clones.

Also, you can write methods that return the internal object without fearing that the caller will then change that object. If the object was mutable, you'd have to make a "defensive copy" of it. But if it's immutable, it's safe to return a reference to the actual internal object.

However, what happens if someone assigned a FlexiblyRoundableDouble to one of your Double fields? That object would be mutable. The clone() would assume it isn't, it will be shared between two objects, perhaps even returned by a method. The caller would then be able to cast it back as a FlexiblyRoundableDouble, change the field... and it will affect other objects that use that same instance.

Therefore, immutable objects should be final.


All this has nothing to do with the constructor issue. Objects can be safely immutable with public constructors (as demonstrated by String, Double, Integer and other standard Java immutables). The static factory method is simply a way utilizing the fact that the object is immutable, and several other objects can hold references to it safely, to create fewer objects with the same value.

like image 123
RealSkeptic Avatar answered May 04 '26 03:05

RealSkeptic