2

I am currently reading here that in order to achieve immutability of my object, I have to:

  1. Declare all my fields private and final
  2. Not define setters

Why do I need to declare the fields final if there are no setters anyways. The java compiler doesn't allow something like this:

myObj.getSomething() = new Somthing()

If I try to use reflection, then the final keyword doesn't stop me from changing the reference.

I found a very nice explanation here why the entire class needs to be final but nothing about why the private fields need to be final.

Edit: As a reply to GotoFinal's comment Here is a class that shows how I can edit the field with reflection:

public class Test {
static class Immutable {
    private final StringBuilder immutableField = new StringBuilder("You can't set final field just by normal reflections");

    public StringBuilder getStringBuilder() {
        return immutableField;
    }
}

public static void main(String[] args) throws Exception {
    Immutable immutableObject = new Immutable();
    Field f1 = immutableObject.getClass().getDeclaredField("immutableField");
    f1.setAccessible(true);
    f1.set(immutableObject, new StringBuilder("Well, I just did"));
    System.out.println(immutableObject.getStringBuilder());
}

}

  • 4
    If they are not final then a sub-class could change them or create set methods. – Joakim Danielson Jul 11 '18 at 10:56
  • As this [comment](https://stackoverflow.com/questions/12306651/why-would-one-declare-an-immutable-class-final-in-java/12306696#12306696) points out, there could be multiple issues if the class itself is not final. As shown in the comment, a subclass could create set methods even if the superclass's fields are final. – Lyubomir Papazov Jul 11 '18 at 11:03
  • @JoakimDanielson fields are private (see OP's point 1), so they cannot be changed by a subclass – Jaroslaw Pawlak Jul 11 '18 at 11:03
  • @JaroslawPawlak, true but you could also add a method to the class itself that modifies them if they are not final. I got the impression the question was about `final` primarily – Joakim Danielson Jul 11 '18 at 11:10
  • It is just for "good practice": making the reader of the code aware that you don't want these variables to change value. But that's important: as important as the runtime considerations. Especially when someone is refactoring this class – David Lavender Jul 11 '18 at 11:34

3 Answers3

4

It does not need to be final, but it is a good practice as when reading source code you instantly know that given field can't change - including inside of class or by local classes - declared inside your class (java will generate special bridge setter for that field then).
Also because field is final you need to initialize it inside constructor - so it is harder to make some error here.

It might also affects how deserializers will work, as most of libraries do not try to modify final fields.

GotoFinal
  • 3,585
  • 2
  • 18
  • 33
  • 1
    I can edit the the final field with reflection, please see my edit. I understand from your comment that having `final` fields it more of a good practice, than a must, am I correct? – Lyubomir Papazov Jul 11 '18 at 11:17
  • 1
    @LyubomirPapazov oh, seems that you are right, sorry. this seems to throw exception only to final static fields. But still - many libraries will act differently for final fields and will not try to change it via reflections. – GotoFinal Jul 11 '18 at 11:25
  • 1
    @LyubomirPapazov if it does compile then nothing is "a must" ;) it is all about good code and good practice. – GotoFinal Jul 11 '18 at 11:32
0

To prevent the fields from being reassigned, you should make them final.

The strategy of just not defining setters is not enough, since:

  • Other developers might add a setter because a field does not express the desire to be immutable
  • Subclasses may define setters and modify the field this way

Declaring the fields as final prevents both of these. Also, it is much easier to check for a final keyword then read the entire class to verify that a setter is absent.

Furthermore, the JVM can apply various optimizations if the field declared as final. I would say reflection is irrelevant here, as anything can be bypassed using it.

Boris van Katwijk
  • 2,998
  • 4
  • 17
  • 32
  • Well, your answer explains why it's a good practice, but not why it's a must. If I don't declare the class itself final, then making the fiends final does not guarantee encapsulation, as in [this](https://stackoverflow.com/questions/12306651/why-would-one-declare-an-immutable-class-final-in-java/12306696#12306696) example. – Lyubomir Papazov Jul 11 '18 at 11:10
  • Its not a must, neither is 'dont define setters' which could be replaced with 'dont call those setters'. The point is, a final keyword does exactly what you want, while 'dont define setters' is in practice a non-enforcable negative. – Boris van Katwijk Jul 11 '18 at 12:31
  • "the JVM can apply various optimizations if the field declared as final" as far as I know java don't do anything special for final fields now. (expect for "constants") as changing final field is pretty easy and JVM does not track such changes. Ofc this can change someday, so just saying. – GotoFinal Jul 11 '18 at 12:51
0

One of the main advantages of immutable classes is that they are inherently thread-safe: if they have no mutable state, there is no way that one thread can affect the behaviour of an instance of that class seen by another thread.

Declaring a field final actually has consequences for the visibility of that field (in the sense of the Java Memory Model, not public/private). A field which is declared final is guaranteed by specification to be initialized before the constructor finishes executing.

What this means is that - provided you don't unsafely publish a reference to the instance prior to the constructor finishing - all threads are guaranteed to see the initialized value of a final field of an instance.

Without the final, there is no such guarantee this means that the instance isn't truly immutable - a thread might read one value from the instance on one occasion, and then a different value from the instance on another.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243