Reputation: 73
i read this , and though one of the answers makes sense, I still feel there's something wrong, so I'll go on and give an example.
suppose you have this class:
public class ClassA {
private List<E> mList;
//Constructor assigns some value to mList...
public List<E> getList() {
return mList;
}
}
This class is said to be immutable , and yet, when I do something like this in another class, say ClassB, stuff happens:
public class ClassB {
//variables and constructors....
public void aFunction(ClassA classAObject) {
List<E> anotherList = classAObject.getList();
//play around with the variable anotherList, and though ClassA is immutable, I can change the value of its mList variable.
}
}
Now I know that I could add that 'final', as mentioned in the link i posted above, but seriously, am I missing something regarding this immutable concept? I mean, is there some reason why it really isn't that immutable?
Upvotes: 1
Views: 150
Reputation: 2613
The class is considered immutable when all its member fields are immutable, both scalar fields and references, but not necessary referenced objects. And list is such referenced, certainly non-trivial, object.
To make immutable also referenced objects, like list you referring, it would require a bit more effort.
If you want to extent to the referenced list, to start with put the final
keyword to mList
declaration, to make the reference safely immutable. OK, now let's secure the list. You can:
mList
at all, perhaps only ClassA.get(index)
delegating to mList.get()
would be enough for your needs. You have to then ensure that list is filled in constructor and there is no other modifying access to mList
.Collections.unmodifiableList(list)
But don't forget that the list again is just a collection of references and you again protected only the references, it guarantees nothing for the referenced objects from the list, the list items.
To make immutable the whole object graph, if it is what you probably want, that would take even more effort. Immutability dos not necessarily come cheap, in terms of development effort and CPU, like to make defensive copies.
Upvotes: 0
Reputation: 30285
The "final" attribute affects only the reference to the list, not the list itself. If you want an immutable list, the List object itself has to be immutable. Thankfully, there are some standard solutions for this:
Collections.unmodifiableList() which is a standard Java wrapper for making list immutable, Or
Google's Guava Immutalble List (this is the most convenient option IMHO), Or
Implement your own list that cannot change after creation
Upvotes: 4
Reputation: 5794
First of all, ClassA is not immutable, nor List contained in it. Immutability for reference types is not possible through "final" definition unless provided within the object as its functionality. In the given example, List can not be immutable because it doesn't designed to be. You may use:
public List<E> getList() {
return Collections.unmodifiableList(list);
}
or
public E[] getList() {
return (E[]) list.toArray();
}
for making list objects -practially, not truly- immutable to prevent changes from outside.
As a general advice, returning collection types as a reference is not a good practice in terms of encapsulation and OOP principles. In this way you:
That's why you have to abstract the internal parts of the object from the outside world and open only required parts. In general, immutability for reference types is more about their abstraction and encapsulation, not to be provided extrinsically.
Upvotes: 1
Reputation: 43651
You can't change the value of mList
, that is, assign a different value to that property. But you can change the contents of mList
.
Return Collections.unmodifiableList(this.mList)
if you want to avoid this.
Check "Effective Java" by Joshua Bloch (specifically "Minimize mutability").
Upvotes: 1