Abu3odeh
Abu3odeh

Reputation: 73

Immutable classes not so immutable

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

Answers (4)

Espinosa
Espinosa

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:

  • Do not expose 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.
  • Create a defensive copy of that list and that you can safely expose
  • Create immutable wrapper adapter around the list, using for example: 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

Malt
Malt

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:

Upvotes: 4

koders
koders

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:

  1. open the internals of your object to outside world,
  2. enable possibly unintended changes (or have to think about and prevent them)
  3. after a certain amount of time (means the code is being called from more and more places) you make your class very difficult to change and adopt future requirements.

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

lexicore
lexicore

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

Related Questions