1

What can you do to make an object such as this immutable? I am mostly concerned about solving public void someMethod(SomeObject someObject) { } <== This case

For example:

public class SomeObject {
   private String someString;

   public void setSomeString(String someString) {
      this.someString = someString;
   }
   public void getSomeString() {
      return someString;
   }
}


public void someMethod() {
   final SomeObject someObject = new SomeObject();
   someObject.set("Want to prevent this"); // <-- SomeObject is mutable in this case
}

public void someMethod(SomeObject someObject) {
   someObject.set("And prevent this!"); // <-- And so is this
}
7
  • 1
    Set the member variables only in the constructor or member declarations. Any object that can be modified after the constructor returns is not (and cannot be) truly "immutable" - objects don't need setters. Also, it sounds like the definition of final should be reviewed (it has nothing to do with "single reference"). Commented May 12, 2015 at 1:43
  • What about a final declaration on an interface of which SomeObject would implement. Commented May 12, 2015 at 1:49
  • final has different meanings, depending on where it is applied (it does not relate to immutability when applied to a class; nor to the immutability of objects named by variables). I have no idea what is meant by "final .. on an interface" (although this question might be an interesting read). Commented May 12, 2015 at 1:50
  • In your example final SomeObject someObject the reference variable someObject is final and not the object it points to. IMO reference variable cannot point to another object but object can be modified. Commented May 12, 2015 at 1:57
  • You are correct @akhil_mittal final only allows the reference to be set once Commented May 12, 2015 at 2:08

1 Answer 1

4

You are right, declaring an object final does not make it immutable. All it does is preventing the final variable from being re-assigned a new object, but the object that is already assigned to it could be mutated if its mutating methods are available.

You can give the object an interface that is immutable, and program to that interface:

interface ImmutableCar {
    String getMake();
    String getModel();
}
class Car implements ImmutableCar {
    public Car(String make, String model) {
        this.make = make;
        this.model = model;
    }
    private String make;
    private String model;
    public String getMake() { return make; }
    public void setMake(String m) { make = m; }
    public String getModel() { return model; }
    public void setModel(String m) { model = m; }
}

If you do it like this

ImmutableCar car = new Car("VW", "Bora");

you would not be able to access mutating methods without an explicit cast. Of course this would not make the object truly immutable, because casting would remain a possibility, but then one could argue that other immutable objects can be changed by going through reflection, so this approach lets you expose only immutable behavior.

Sign up to request clarification or add additional context in comments.

10 Comments

final ImmutableCar car = new Car("VW", "Bora"); would be able to prevent any recasting... do we have an immutable car?
@shinjw Not really: one would be able to write ((Car)car).setMake("Honda") even if car is declared final.
I get your point but the question seems a little odd to me. I mean, it could be me, but why would you expose mutators to a class which objects you wish to be immutable? Or should this specific instance be made immutable? Either way, no class can have trully imutable objects if it allows subclassing.
One case would be an object passed through a method... That object is mutable in this case because that value of the reference is what is actually passed. I agree with using an interface to hide the mutable aspects of the object
Just adjusted the question.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.