Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

making a class immutable in java

To make a class immutable what I can do is:

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

But if my class has another object of some other class then , somone can change value of that 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?

}
}
like image 269
user93796 Avatar asked Mar 19 '12 03:03

user93796


3 Answers

A) Make the OtherClass immutable as well

or

B) Don't allow direct access to the OtherClass object, instead providing only getters to act as a proxy.

Edit to add: You could make a deep copy of OtherClass and return a copy rather than the original, but that generally isn't the type of behavior you would expect in Java.

like image 173
Brian Roach Avatar answered Oct 20 '22 21:10

Brian Roach


Immutability is best considered from the perspective of the API user. So your object API needs to satisfy the following two conditions:

  1. No way for an external user to change the value of the object
  2. A guarantee that any time the user reads or makes use of the object's value in the future, it will get the same result

Important note: It is in fact OK to have mutable data inside an immutable object as long as it behaves as an immutable object from the perspective of the API user. Consider java.lang.String for example: although it is generally considered as the definitive immutable class, it does in fact have a mutable internal field for caching the hashCode (not many people know this!).

So to address your question, if you wish to contain another (mutable) object inside an immutable object then you typically need to do one or more of the following:

  • Guarantee that nobody else can change the value of the mutable object. Typically this means ensuring that no-one else can have a reference to the mutable object, so this is only usually possible if you create the object yourself rather than accept a reference from outside.
  • Take a defensive deep copy of the mutable object, and don't hand out references to the new copy. Only allow operations that read the new copy in the public API. If you need to hand out a reference to this object, then you need to take another defensive copy (to avoid handing out a reference to the internal copy).
  • Use an immutable wrapper for the mutable object. Something like Collections.unmodifiableList. This is useful if you want to hand out a reference to the internal mutable object but don't want to run the risk of it being modified.

All of these solutions are a bit hacky - a better solution overall is to avoid the use of mutable objects within immutable objects. In the long run it's asking for trouble because sooner or later a mutable reference will leak out and you will have an extremely hard to find bug. You are better moving towards a full hierarchy of immutable objects (the approach taken by languages like Scala and Clojure)

like image 42
mikera Avatar answered Oct 20 '22 21:10

mikera


I assume OtherClass (by the way you say Other once) is meant to be a class you don't control, or which has to have a setter.

If you can't remove getOther, change it to getOtherView and return a read-only view of other. There will be wrappers for all the get methods, but no set ones.

like image 37
Matthew Flaschen Avatar answered Oct 20 '22 19:10

Matthew Flaschen