Search code examples
javaclassimmutabilityfinal

Immutable class in Java


As per many documentations, I have seen that an immutable class should have the following features:

  1. class should be final

  2. all the methods should be final

  3. all the variables should be final

  4. there should not be any setters

But my questions are:

  1. What if I have a class with only final variables?

  2. If I do have setters also, I cannot change the state of the Object as I have all the final variables. So how will this affect immutability?

  3. How can inheritance change the object state in this case?


Solution

  • 1.What if I have a class with only final variables?

    That will get you far but not all the way. The types of those variables also need to be immutable. Consider for instance

    class MyImmutableClass {
        // final variable, referring to a mutable type
        final String[] arr = { "hello" };
    
        // ...
    }
    

    This allows someone to do

    myImmutableObject.arr[0] = "world";
    

    and effectively mutate objects of your immutable class.

    Also, it's recommended prohibit extending the class (because there's no way to force subclasses to be immutable). See answer to your third question below.

    1. If I do have setters also, I cannot change the state of the Object, As i have all the final variables. so how will this affect immutability.

    That's right. If all variables are final, standard setter methods can't exist.

    1. how can inheritance change the object state in this case?

    A subclass can't change the state of final fields of the super class. But there's another issue with inheritance.

    If you have an immutable Animal subclassed by a Dog, and the Dog has a setDogsName method that mutates the object, then in effect you may have Animal objects (of type Dog) that are in fact mutable.

    In other words most (all?) benefits of immutability is lost if an immutable class is open for extension: If you receive an Animal as a parameter to a method for instance, you can't assume it's immutable. You can't safely put Animal objects as keys in hash maps, etc.


    Basically the original statements are a bit redundant, which is why I think they are a bit confusing:

    • A final class can't be extended, so it's redundant to also mark the methods as final
    • If all variables are final, then it's kind of redundant to say that there should be no setters.

    Also, these are sufficient constraints, but not necessary. You can for instance have immutable classes without final variables / final field types as long as they are private, never changed internally and never leaked to outsiders.