3

So, I read somewhere that there are 3 requirements for a class to be immutable in Java.

  1. All data fields must be private.
  2. There can't be any mutator methods for data fields.
  3. No accessor methods can return a reference to a data field that is mutable.

But I don't agree with #2 because even if a class has mutator methods, it can be immutable as long as those mutator methods are private. Am I right or wrong? Can you explain in detail?

NewLearner
  • 153
  • 11
  • 5
    if it has a private mutator, the state can change, so, no. – Stultuske Sep 18 '18 at 09:00
  • 1
    I do not exactly agree with all the other answers in here so far. Yes, the state cannot change in any way for the object to be immutable. That said, not all fields need to be counted as state. See e.g. `String`'s `hash` field which is cached, precomputed on the first `hashCode()` invocation. And yet, `String` is immutable because the field is not part of the logical state of the object. It's a mere performance optimization, a cache, in the current OpenJDK. – Petr Janeček Sep 18 '18 at 09:12
  • Stultuske: can you give me a specific example how you can change a 'class' that only has a private mutator with private data fields? – NewLearner Sep 18 '18 at 09:15
  • Petr Janeček: Are you talking about immutable object? I'm asking about immutable class. – NewLearner Sep 18 '18 at 09:16
  • @NewLearner Sorry, that's was just a slightly incorrect terminology on my side. By "immutable object" I meant instances of an immutable class. If your class has a private mutator that is being used to do some work *which does not change the logical state* of the object, it might be fine. If it changes the state in a way that's observable from the outside, your object is not immutable anymore. Also note that you want your fields final. The semantics of final fields are useful for concurrency: https://shipilev.net/blog/2014/safe-public-construction/#_safe_initialization. – Petr Janeček Sep 18 '18 at 09:24
  • Petr Janeček: I see. so can you give me a specific example of the situation where a class is not an immutable class even if all the fields and setter methods are private? – NewLearner Sep 18 '18 at 09:28
  • @NewLearner Here the [example](https://ideone.com/SBjJy1) you asked for. – LuCio Sep 18 '18 at 11:09
  • @LuCio: Wow. Thank you! Perfect answer! No one else could explain it fully. – NewLearner Sep 18 '18 at 15:41
  • @NewLearner Good to know the example helped you to understand the reasons for the three requirements. The discussion has got very exciting. – LuCio Sep 18 '18 at 16:22

7 Answers7

1

EDIT

But I don't agree with #2 because even if a class has mutator methods, it can be immutable as long as those mutator methods are private

Because it is a private mutator does not guarantee that it does not change state, but as long as it does not change state what it it supposed to remain intact we can take as immutable. because immutability is remaining intact once set.

Immutable only has a getter. There's no way to change the value of its fields once it's set.

Lets take String class, it is immutable

Once a String object is created, it is not allowed to change. It cannot be made larger or smaller, and you cannot change one of the characters inside it. You can think of a string as a storage box you have perfectly full and whose sides can't bulge. There's no way to add objects, nor can you replace objects without disturbing the entire arrangement.

so immutablity of a class should be like that.

The Scientific Method
  • 2,374
  • 2
  • 14
  • 25
  • 2
    And yet, there is an internal field of the `String` class, the `hash` field, which changes during the lifetime of a string object. The field is not part of the logical state of the object, and serves as a performance optimization tool with no visible effects to the outside world... So if there is a private mutator which does not change the logical state of the object in question, it might be still be a fine immutable object. – Petr Janeček Sep 18 '18 at 09:18
  • 1
    As far as a class ensures to outside world that it remains intact, that is immutability, i got what you said, – The Scientific Method Sep 18 '18 at 09:30
  • @The Scientific Method: Can you just give me ONE specific example of a class being mutable where the class has '1. only has private fields. 2. only has private setter methods. 3. does not have fields that reference to a mutable objects – NewLearner Sep 18 '18 at 10:55
  • please check the source code for `String` class, you may get answers there. http://hg.openjdk.java.net/jdk7u/jdk7u6/jdk/file/8c2c5d63a17e/src/share/classes/java/lang/String.java – The Scientific Method Sep 18 '18 at 11:04
  • the class you are referring is unusable if it meets `1. only has private fields. 2. only has private setter methods. 3. does not have fields that reference to a mutable objects`, it should expose some behavior through pubic method to be usable. – The Scientific Method Sep 18 '18 at 11:09
1

There are different possible definitions of immutability.

The definition you mention does not allow any state change of an object. In particular, after it has been created, it cannot modify its own state.

However, sometimes, an immutable object is defined as an object whose state cannot be observed to change. When immutability is defined like this, the state of an immutable object is allowed to change if this state change cannot be observed from the outside. For example results of expensive calculations could be cached, or some internal statistic information could be recorded, or something like that.

One advantage of immutable objects which is often stated is that they are automatically thread-safe. It is important to note that this advantage only holds when you define immutability in the strong way (the first option above). If an object which only changes its non-observable state is accessed concurrently by two threads, it could in principle still produce erroneous results, so the programmer must take additional care that the object is thread-safe.

Hoopje
  • 12,677
  • 8
  • 34
  • 50
0

There are other ways to break your immutable object. For instance, reflection API. I believe if you decided to make it immutable, would you mind to erase the private setter method. It just doesn't make sense to keep it there.

  • "I believe if you decided to make it immutable, would you mind to erase the private setter method. " -> I have no idea what that means. Are you asking if I would mind erasing the private setter method? I just told you that I think tthe class can be still immutable even if it has private methods. not sure if you're re-asking a question to make a point or if there's even a point. can you just explain concisely why a private setter method makes the class mutable? – NewLearner Sep 18 '18 at 09:12
0

Directly taken from Wikipedia:

In object-oriented and functional programming, an immutable object (unchangeable object) is an object whose state cannot be modified after it is created.

So definitely if you have a class with a mutator method that changes state of the object (intended as class instance) then that class is not immutable. To consider it as immutable every method must not change its state, but produce another object of the same class, with the modification applied.

Lorelorelore
  • 3,335
  • 8
  • 29
  • 40
  • I was asking about immutable class opposed to immutable object. – NewLearner Sep 18 '18 at 09:13
  • An immutable object is an instance of an immutable class. – Lorelorelore Sep 18 '18 at 09:27
  • and I was asking about a class being immutable opposed to an 'object' being immutable. – NewLearner Sep 18 '18 at 09:33
  • So what? An object is immutable if it is an instance of an immutable class. – Lorelorelore Sep 18 '18 at 09:49
  • I already read it. You should notice that the requirements for a class for being immutable reflects directly on the objects which are instance of the class. The two concepts are pretty the same thing. The definition is clear. – Lorelorelore Sep 18 '18 at 10:03
  • Do not intend object and class as two separated things. Immutability is a design principle, so if a class has a method that changes internal fields it means that at runtime you can change the state of the instances of that class without creating new instances of that class. This is mutable state. – Lorelorelore Sep 18 '18 at 10:07
0

Yes, there can't be any mutator methods for data fields.

The reason is that setting the method private only effects the scope of the method. If you want a truly immutable variable then you must set variable final as well. This way your variable cannot be mutated.

Raj
  • 707
  • 6
  • 23
  • not really. it can't be re-referenced, but the state of the variable can change. – Stultuske Sep 18 '18 at 09:13
  • i meant that variable should be set as final. – Raj Sep 18 '18 at 09:15
  • Adding "final" keyword doesn't make a variable immutable. If you have a List assigned to some variable it will be mutable even with "final" keyword - you can still add/change elements of the List - the state changes. – Amongalen Sep 18 '18 at 09:24
  • @Raj yes, I know, but you also said: "This way your variable cannot be mutated", which is not entirely correct. – Stultuske Sep 18 '18 at 09:28
  • Amongalen: Thank you for the great point. I don't think anyone else knew that. – NewLearner Sep 18 '18 at 09:29
  • @Amongalen Making my variable private and final should make it immuatble isnt it? See this https://stackoverflow.com/questions/18194139/make-immutable-java-object – Raj Sep 18 '18 at 09:36
  • @Stultuske Making my variable private and final should make it immuatble isnt it? See this stackoverflow.com/questions/18194139/make-immutable-java-object – Raj Sep 18 '18 at 09:36
  • @Raj if you don't write code in the class that changes the state, yes. but simply not putting setters doesn't guarantee that. private and final are fine, but it's quite easy to write code that still changes the state of such variables – Stultuske Sep 18 '18 at 09:40
  • @Stultuske correct I understand that, but the question here was related to setters only that is why I have specified same. Thanks. – Raj Sep 18 '18 at 09:45
  • @NewLearner practically everybody knows that. final means you can't change the reference of the variable. it doesn't mean the variable becomes a constant. That's only the case when the variable is either a primitive type, or an immutable type – Stultuske Sep 18 '18 at 09:46
  • @Raj It is only enough as long as the type of a given variable is immutable itself. In your example the person is using Strings which are immutable themselves and that class is indeed immutable. Imagine adding a list of hobbies to that class. You make it private and final and provide no way to modify that list (no add or remove). There is no method that returns that list, just one that concatenates all elements into a String. Finally you want to be able to sort those hobbies (which modifies the list - changes object's state). That class is not immutable because of that sorting method. – Amongalen Sep 18 '18 at 09:52
  • @Raj what exactly do you mean by "The reason is that setting the method private only effects the scope of the method"? Give me ONE specific example of a class being mutable where the class has '1. only has private fields. 2. only has private setter methods. 3. does not have fields that reference to a mutable objects. – NewLearner Sep 18 '18 at 10:39
  • @NewLearner I meant that there shouldn't be any mutator method at all. – Raj Sep 18 '18 at 10:41
  • @Raj and I'm asking "why" there shouldn't be any mutator method at all. – NewLearner Sep 18 '18 at 10:43
  • @Raj Can you just give me ONE specific example of a class being mutable where the class has '1. only has private fields. 2. only has private setter methods. 3. does not have fields that reference to a mutable objects. – NewLearner Sep 18 '18 at 10:43
0

Actually what is the point of private mutators?

Immutable means that the object's state can't change in any way after it's creation. Doesn't matter if it's via direct access to the fields, through mutators or some other "random" method that changes the state. None of this is allowed for a class to be immutable.

Amongalen
  • 3,101
  • 14
  • 20
-1

Immutable doesn't mean: another class can't change the state of this Object, it means: The state of this Object can never change.

Consider this code:

public Person {

  private String name;

  public Person(String name) {

    this.name = name;

  }

  private void setName(String name) {
    this.name = name;
  }

  public boolean hasName(String name) {
    boolean result = this.name.equals(name);
    this.name = name;
    return result;
  }
}

This can't be considered an Immutable class, since even if it doesn't seem so to the class that calls hasName(String name), the state of the Object changes. Seeing that normally, an immutable class usually has it's members declared as final, this would not even compile.

Stultuske
  • 9,296
  • 1
  • 25
  • 37
  • "an immutable class usually has its members declared as final" -> what do you mean by 'members'? methods? data fields? instances? – NewLearner Sep 18 '18 at 09:10
  • I mean that in an immutable class, the state of the members may not change, so they are declared final, to make sure they never will change. final variables can not be re-referenced – Stultuske Sep 18 '18 at 09:12
  • Do you have any specific example of a class being mutable even if all the fields are private and all the setter methods are private as well and there's no object variable to a mutable datafield ? – NewLearner Sep 18 '18 at 09:32
  • @NewLearner there's an example of that in my answer. Didn't you see it? – Stultuske Sep 18 '18 at 09:41
  • "the state of the Object changes." -> can you be more specific? the state of the Object goes from 'what' to 'what'? trying to understand this clearly. – NewLearner Sep 18 '18 at 10:08
  • check the hasName method. the state of the object changes, because the name is set to the value that is passed as parameter to the method – Stultuske Sep 18 '18 at 10:09
  • hasName is a setter method and you set the setter method public. – NewLearner Sep 18 '18 at 10:35
  • @NewLearner hasName is NOT a setter method. it was a simplistic way of showing setters are not the only methods that are capable of changing the state of your class – Stultuske Sep 18 '18 at 10:38
  • hasName changes the value of a variable by replacing the value by the parameter value. Isn't that a definition of setter method? a method that updates/changes the value of variables? – NewLearner Sep 18 '18 at 10:48
  • @NewLearner nope. a setter doesn't return anything. a setter only sets. let's say you have a method of about 350 lines long (it's hell, but they do exist), which perform all kinds of tests and algorithms, which change (sometimes) the state of your class, and always return a value, would you consider that to be a setter? – Stultuske Sep 18 '18 at 10:55
  • yes I would if it was up to me. Because one person can be a father, a doctor, a son, a citizen all simultaneously and just like that, a method can be a 'setter' while being so many other things at the same time. Is there a technical definition that says a setter method cannot return any value and it always has to be void? – NewLearner Sep 18 '18 at 23:46
  • then I recommend you re-read up on setters and getters. Just because a method returns a getter, does NOT make it a getter. Just because a method sets a value, does NOT make it a setter. The only way you know this method sets a value, is because you see the code. Remember that in 99% of the time, you won't know the code you call. Yes, there are technical descriptions about setter and getter. – Stultuske Sep 19 '18 at 05:53
  • Also, to follow your explanation: yup, a person can be both a father and a son at the same time, but the chance of a person becoming a father and a person at the same time, is non-existent, so, if you want to store the father-link in that object (which you probably won't), you would have to change the state of that Object – Stultuske Sep 19 '18 at 05:55