ravinder reddy
ravinder reddy

Reputation: 318

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?

Upvotes: 3

Views: 764

Answers (3)

aioobe
aioobe

Reputation: 420951

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.

Upvotes: 4

Stephen C
Stephen C

Reputation: 718718

An immutable class is one that you cannot change. Achieving immutability is a matter of eliminating possible ways of changing an object's state. That can be achieved by a combination of structural and behavioural means.


But first, lets look at the "should have" list:

  • "class should be final" - This may be advisable, but it may not be strictly necessary ... or even desireable. An instance1 of a class can be immutable even if instances of some subclasses are mutable. It all depends on which classes need to be immutable, and that depends on the context.

  • "all the methods should be final" - Neither necessary or sufficient. If the class is final then it is unnecessary. If the class is NOT final, then it is not sufficient. (You can add methods with different signatures in a subclass.)

  • "all the variables should be final" - Neither necessary or sufficient. You can have an immutable class whose fields are not final, and a mutable class whose fields are all final.

  • "there should not be any setters" - It depends on what you mean by a "setter", but once again this is neither necessary (for some models of mutability) or sufficient.


Your Questions:

1) What if i have a class with only final variables ?

That is not sufficient to guarantee immutability. For example, if one of the final variables is an array, then the state of that array could be changed, thereby changing the state of the object as a whole. This could be done by a setter (or any other method of the class), or if the class is a "leaky abstraction" then it could done by external code.

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 immutablity.

See above. Declaring all fields as final is not a guarantee of immutability. A setter could change the state of a mutable component of the object.

3) how can inheritence change the object state in this case?

It can't1. But that's not the point.

The reason for making an immutable class final is to stop someone creating a mutable subclass of the class.

Why does that matter?

Well, suppose that a method requires parameters to be immutable (e.g. for security). If you declare it with an immutable class that is not final, then someone create an mutable subclass and pass an instance of that instead of the original immutable class.

This is the main reason why (for example) the String class is final.


1 - I need to qualify this. It depends on whether we are talking about instances whose class is A, or about instances that are type compatible with A. I'm talking about the former. The fact that there is a mutable subclass does affect the mutability of an instance whose class is A.

Upvotes: 2

TheLostMind
TheLostMind

Reputation: 36304

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 immutablity.

final is at reference level and immutability is at instance level.

class someMutableClass{
final List someList;
}

In the above piece of code. If the reference of the list escapes, then anyone can do : someList.add(someValue)

But they cannot do :

someList=someOtherList;

That is the difference.

how can inheritence change the object state in this case?

The child class can access certain fields of the parent class and then change it. You can can make a parent class reference point to a child class object and modify its fields. So, to ensure immutability, you have to ensure that the child class doesn't alter anything in the parent. So make it final.

Upvotes: 2

Related Questions