Creating a class immutable in java

To make the class immutable, what I can do is:

1) Make the class final
2) do not provide setters
3) mark all variables as final

But if my class has another object of another class, then somone can change the value of this object

class MyClass{ final int a; final OtherClass other MyClass(int a ,OtherClass other){ this.a = a; this.other = other; } int getA(){ return a; } OtherClass getOther(){ return other; } public static void main(String ags[]){ MyClass m = new Myclass(1,new OtherClass); Other o = m.getOther(); o.setSomething(xyz) ; //This is the problem ,How to prevent this? } } 
+7
source share
8 answers

A) Make OtherClass immutable as well

or

B) Do not allow direct access to the OtherClass object, instead providing only getters to act as proxies.

Edit to add: You can make a deep copy of OtherClass and return the copy, not the original, but as a rule, this is not the type of behavior that you expect in Java.

+3
source

Inevitability is best viewed from the perspective of a user API. Therefore, the API of your object must satisfy the following two conditions:

  • Do not allow anyone to change the value of an object
  • It guarantees that at any time when the user reads or uses the value of the object in the future, he will get the same result

Important Note . In fact, it is normal to have mutable data inside an immutable object if it behaves like an immutable object from the point of view of the API user. For example, consider java.lang.String: although it is usually regarded as the final immutable class, in fact it has a mutable hashCode internal cache field (few know that!).

So, to solve your question, if you want to contain another (mutable) object inside an immutable object, you usually need to do one or more of the following:

  • Ensure that no one else can change the value of the mutable object. Usually this means that no one can reference the mutable object, so this is usually only possible if you create the object yourself, and not accept the link from the outside.
  • Make a protective deep copy of the mutable object and do not pass links to the new copy. Allow only operations that read a new copy in the public API. If you need to transfer the link to this object, you need to take one more protective copy (so as not to transfer the link to the internal copy).
  • Use immutable wrapper for mutable object. Something like Collections.unmodifiableList . This is useful if you want to pass a reference to an internal mutable object, but do not want to expose it to the risk of changes.

All of these solutions are a bit hacky - the best solution overall is to avoid using mutable objects in immutable objects. In the end, he asks for trouble, because sooner or later the volatile link will be changed, and it will be very difficult for you to find the error. You better move to a complete hierarchy of immutable objects (an approach used by languages ​​such as Scala and Clojure)

+2
source

I assume that OtherClass (by the way, you say "Another once") means a class that you do not control, or which the installer should have.

If you cannot remove getOther , change it to getOtherView and return the read-only view to other . There will be wrappers for all get methods, but not set.

+1
source

Bring back deep clones from your getters. You may find that this is not an easy task.

+1
source

All objects referenced in an immutable class must be immutable or, at least, encapsulated as private and make sure that they are not changed (not inside the methods of your class, but definitely not from the outside). For example, if you have a situation like this:

 public class MyImmutable { private MutableClass mutableObject; } 

... You cannot provide the getMutableObject() method, because it will open the door for external modifications, for example:

 myImmutable.getMutableObject().setSomeAttribute(newValue); 

As a special case above, all collections and / or maps must be immutable using the ummodifiableXXX() methods in the Collections class.

+1
source

you cannot (reasonably) stop this in java. if you don't have control over another class, there are ways to effectively get consistent behavior, but in practice it can be very expensive. in principle, you should always return a copy of this class in any public method return methods. (jdk really has this problem with the TimeZone class).

+1
source

But if my class has another object of another class, then somone can change the value of this object ...

Java objects are not primitive. If you marked a primitive as final, then its value cannot be changed after its assignment. However, the contents of an object cannot be final, only references to objects can be final. Therefore, you cannot create an object this way.

One solution may be to abandon all setter / mutator methods that can modify specific fields of an object and encapsulate them in such a way that you can only access them, not change them.

+1
source

You can create an immutable class in java in the following ways:

1. Do not provide setter methods.

2.Paste all fields as final and private.

3. Make Class as final.

+1
source

All Articles