Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an immutable object without final fields?

Can we create an immutable object without having all fields final?

If possible a couple of examples would be helpful.

like image 540
Vinoth Kumar C M Avatar asked Sep 21 '11 13:09

Vinoth Kumar C M


People also ask

Can we create immutable class without final keyword?

No, it is not mandatory to have all properties final to create an immutable object. In immutable objects you should not allow users to modify the variables of the class. You can do this just by making variables private and not providing setter methods to modify them.

Why are immutable fields final?

An object (class or instance) is immutable, if its internal state cannot be changed (reflection doesn't count). Making a field final guarantees only that the value (if it's a primitive) or reference (for non-primitives) cannot be changed.

What is required to create an immutable object in Java?

To create an immutable class in Java, you have to do the following steps. Declare the class as final so it can't be extended. Make all fields private so that direct access is not allowed. Don't provide setter methods for variables.


2 Answers

Declare all fields private and only define getters:

public final class Private{
    private int a;
    private int b;

    public int getA(){return this.a;}
    public int getB(){return this.b;}
}

citing @Jon Skeet's comment, final class modifier is useful for:

While an instance of just Private is immutable, an instance of a subclass may well be mutable. So code receiving a reference of type Private can't rely on it being immutable without checking that it's an instance of just Private.

So if you want to be sure the instance you are referring to is immutable you should use also final class modifier.

like image 155
Heisenbug Avatar answered Oct 24 '22 13:10

Heisenbug


Yes, it is - just make sure that your state is private, and nothing in your class mutates it:

public final class Foo
{
    private int x;

    public Foo(int x)
    {
        this.x = x;
    }

    public int getX()
    {
        return x;
    }
}

There's no way of mutating the state within this class, and because it's final you know that no subclasses will add mutable state.

However:

  • The assignment of non-final fields doesn't have quite the same memory visibility rules as final fields, so it might be possible to observe the object "changing" from a different thread. See section 17.5 of the JLS for more details on the guarantees for final fields.
  • If you're not planning on changing the field value, I would personally make it final to document that decision and to avoid accidentally adding a mutating method later
  • I can't remember offhand whether the JVM prevents mutating final fields via reflection; obviously any caller with sufficient privileges could make the x field accessible in the above code, and mutate it with reflection. (According to comments it can be done with final fields, but the results can be unpredictable.)
like image 44
Jon Skeet Avatar answered Oct 24 '22 14:10

Jon Skeet