By DRastislav


2013-04-17 13:13:29 8 Comments

Must immutable objects have all properties be final?

According to me not. But I don't know, whether I am right.

8 comments

@amitkumar12788 2019-01-24 22:23:59

Not necessary, you can achieve same functionality by making member as non-final but private and not modifying them except in constructor. Don't provide setter method for them and if it is a mutable object, then don't ever leak any reference for that member.

Remember making a reference variable final, only ensures that it will not be reassigned a different value, but you can still change individual properties of an object, pointed by that reference variable. This is one of the key points.

@Tarun Bedi 2016-07-22 11:29:48

String class is Immutable but property hash is not final

Well it is possible but with some rules/restrictions and that is access to mutable properties/fields must provide same result every time we access it.

In String class hashcode actually calculated on the final array of characters which is not going to change if String has constructed. Therefore immutable class can contain mutable fields/properties but it has to make sure that access to field/property will produce the same result every time it is accessed.

To answer your question it is not mandatory to have all the fields final in a immutable class.

For further reading visit here [blog] : http://javaunturnedtopics.blogspot.in/2016/07/string-is-immutable-and-property-hash.html

@ZhekaKozlov 2013-04-24 10:54:35

No.

For example, see the implementation of java.lang.String. Strings are immutable in Java, but the field hash is not final (it is lazily computed the first time hashCode is called and then cached). But this works because hash can take on only one nondefault value that is the same every time it is computed.

@millimoose 2013-04-17 13:19:46

You can easily guarantee immutability by encapsulation alone, so it's not necessary:

// This is trivially immutable.
public class Foo {
    private String bar;
    public Foo(String bar) {
        this.bar = bar;
    }
    public String getBar() {
        return bar;
    }
}

However, you also must guarantee it by encapsulation in some cases, so it's not sufficient:

public class Womble {
    private final List<String> cabbages;
    public Womble(List<String> cabbages) {
        this.cabbages = cabbages;
    }
    public List<String> getCabbages() {
        return cabbages;
    }
}
// ...
Womble w = new Womble(...);
// This might count as mutation in your design. (Or it might not.)
w.getCabbages().add("cabbage"); 

It's not a bad idea to do so to catch some trivial errors, and to demonstrate your intent clearly, but "all fields are final" and "the class is immutable" are not equivalent statements.

@amarnath harish 2018-09-08 17:34:50

in the first case someone can extend the class and change subclass's state and assign to parent class reference thus changing state.

@millimoose 2018-09-09 01:22:17

Yes, but it depends on the context if you think the rogue subclasser is a likely scenario. Declaring a class as final or adhering to the open-closed principle in code review would address that. That said the child class cannot change the value of bar in any case legitimately, so Foo as declared is immutable, and I have a hunch will appear so to all clients of such an object through the interface exposed by Foo.

@millimoose 2018-09-09 01:27:32

Actually this might even adhere to the OCP. It’s not great design but in effect it’s as if you bundled two independent objects, one mutable and one not, under one reference

@assylias 2013-04-17 13:15:53

The main difference between an immutable object (all properties final) and an effectively immutable object (properties aren't final but can't be changed) is safe publication.

You can safely publish an immutable object in a multi threaded context without having to worry about adding synchronization, thanks to the guarantees provided by the Java Memory Model for final fields:

final fields also allow programmers to implement thread-safe immutable objects without synchronization. A thread-safe immutable object is seen as immutable by all threads, even if a data race is used to pass references to the immutable object between threads. This can provide safety guarantees against misuse of an immutable class by incorrect or malicious code. final fields must be used correctly to provide a guarantee of immutability.

As a side note, it also enables to enforce immutability (if you try to mutate those fields in a future version of your class because you have forgotten it should be immutable, it won't compile).


Clarifications

  • Making all the fields of an object final does not make it immutable - you also need to make sure that (i) its state can't change (for example, if the object contains a final List, no mutating operations (add, remove...) must be done after construction) and (ii) you don't let this escape during construction
  • An effectively immutable object is thread safe once it has been safely published
  • Example of unsafe publication:

    class EffectivelyImmutable {
        static EffectivelyImmutable unsafe;
        private int i;
        public EffectivelyImmutable (int i) { this.i = i; }
        public int get() { return i; }
    }
    
    // in some thread
    EffectivelyImmutable.unsafe = new EffectivelyImmutable(1);
    
    //in some other thread
    if (EffectivelyImmutable.unsafe != null
        && EffectivelyImmutable.unsafe.get() != 1)
        System.out.println("What???");
    

    This program could in theory print What???. If i were final, that would not be a legal outcome.

@Eugene 2013-04-17 13:26:46

while I do agree with u, what about an object that has an array field that is final? The reference is immutable, but the values are not. Same thing about ImmutableList of StringBuilders for example. Are these objects considered thread-safe?

@NimChimpsky 2013-04-17 13:39:51

how will an object with non final private fields (initialized on object construction) ever be thread unsafe ?

@assylias 2013-04-17 13:42:06

If all their fields are final they can still be safely published but it is not enough to make them thead safe.

@NimChimpsky 2013-04-17 13:56:04

In what situation would they be thread unsafe ? Nothing can change after object creation ... so I don't undestand how they would ever be unsafe.

@assylias 2013-04-17 14:07:30

@NimChimpsky I have clarified how an effectively immutable object could cause thread safety issues.

@supercat 2013-08-19 16:52:41

If an immutable class uses an array to encapsulate a sequence of values, how should it ensure that writes to array elements will be visible before the class gets exposed to outside code?

@user195488 2013-04-17 13:19:29

Simply declaring an object as final does not make it inherently immutable. Take for example this class:

import java.util.Date;

/**
* Planet is an immutable class, since there is no way to change
* its state after construction.
*/
public final class Planet {

  public Planet (double aMass, String aName, Date aDateOfDiscovery) {
     fMass = aMass;
     fName = aName;
     //make a private copy of aDateOfDiscovery
     //this is the only way to keep the fDateOfDiscovery
     //field private, and shields this class from any changes that 
     //the caller may make to the original aDateOfDiscovery object
     fDateOfDiscovery = new Date(aDateOfDiscovery.getTime());
  }

  /**
  * Returns a primitive value.
  *
  * The caller can do whatever they want with the return value, without 
  * affecting the internals of this class. Why? Because this is a primitive 
  * value. The caller sees its "own" double that simply has the
  * same value as fMass.
  */
  public double getMass() {
    return fMass;
  }

  /**
  * Returns an immutable object.
  *
  * The caller gets a direct reference to the internal field. But this is not 
  * dangerous, since String is immutable and cannot be changed.
  */
  public String getName() {
    return fName;
  }

//  /**
//  * Returns a mutable object - likely bad style.
//  *
//  * The caller gets a direct reference to the internal field. This is usually dangerous, 
//  * since the Date object state can be changed both by this class and its caller.
//  * That is, this class is no longer in complete control of fDate.
//  */
//  public Date getDateOfDiscovery() {
//    return fDateOfDiscovery;
//  }

  /**
  * Returns a mutable object - good style.
  * 
  * Returns a defensive copy of the field.
  * The caller of this method can do anything they want with the
  * returned Date object, without affecting the internals of this
  * class in any way. Why? Because they do not have a reference to 
  * fDate. Rather, they are playing with a second Date that initially has the 
  * same data as fDate.
  */
  public Date getDateOfDiscovery() {
    return new Date(fDateOfDiscovery.getTime());
  }

  // PRIVATE //

  /**
  * Final primitive data is always immutable.
  */
  private final double fMass;

  /**
  * An immutable object field. (String objects never change state.)
  */
  private final String fName;

  /**
  * A mutable object field. In this case, the state of this mutable field
  * is to be changed only by this class. (In other cases, it makes perfect
  * sense to allow the state of a field to be changed outside the native
  * class; this is the case when a field acts as a "pointer" to an object
  * created elsewhere.)
  */
  private final Date fDateOfDiscovery;
}

@Eugene 2013-04-17 13:16:44

Immutable objects MUST not be modified in any way after their creation. final of course helps to achieve that. You guarantee that they will not ever be changed. BUT what if you have an array inside your object that is final? Of course the reference is not changable, but the elements are. Look here at almost the same question I gave also:

Link

@Kai 2013-04-17 13:15:08

Immutable = not changeable. So making properties final is a good idea. If not all properties of an object are protected from being changed I wouldn't say the object is immutable.

BUT an object is also immutable if it doesn't provide any setters for it's private properties.

@Amar Magar 2016-01-21 11:46:25

i have a question: how we can achieve functionality like string class for ex. in case of string class String firstname = new String("amar"); String name ="amar"; so both firstname and name will point to the same memory location on stack please help

Related Questions

Sponsored Content

14 Answered Questions

[SOLVED] Difference between final and effectively final

49 Answered Questions

[SOLVED] Does a finally block always get executed in Java?

26 Answered Questions

[SOLVED] In Java, what is the best way to determine the size of an object?

  • 2008-09-09 17:07:03
  • Jay R.
  • 293102 View
  • 621 Score
  • 26 Answer
  • Tags:   java memory

28 Answered Questions

[SOLVED] Sort ArrayList of custom Objects by property

12 Answered Questions

22 Answered Questions

[SOLVED] What is the point of "final class" in Java?

  • 2011-03-03 13:52:23
  • newbie
  • 454030 View
  • 571 Score
  • 22 Answer
  • Tags:   java final

15 Answered Questions

[SOLVED] Is a Java string really immutable?

18 Answered Questions

[SOLVED] How does the "final" keyword in Java work? (I can still modify an object.)

  • 2013-03-27 09:02:18
  • G.S
  • 474287 View
  • 484 Score
  • 18 Answer
  • Tags:   java final

3 Answered Questions

[SOLVED] non final - immutable classes

Sponsored Content