Reputation: 318
As per many documentations, I have seen that an immutable class should have the following features:
class should be final
all the methods should be final
all the variables should be final
there should not be any setters
But my questions are:
What if I have a class with only final variables?
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?
How can inheritance change the object state in this case?
Upvotes: 3
Views: 764
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.
- 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.
- 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:
final
class can't be extended, so it's redundant to also mark the methods as final
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
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
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