0

I am required to implement an Immutable List interface and modify its methods to ensure immutability of a list.

I think I have managed to do so, but having trouble ensuring such immutability of mutable objects that are found in this list.

Consider the below interface:

public interface ImmutableListInterface<T>{

        T get(int index);

}

and its implementation:

public final class ImmutableList<T> implements ImmutableListInterface<T>{

    private final List<T> immutableList; 

    public ImmutableList(List<T> list) {
        immutableList = list;
    }

    @Override
    public T get(int index) {

        T item;
        List<T> temp = new ArrayList<>(immutableList);

        try {
            //Try retrieving item
            item = temp.get(index);

        }catch(Exception e) {
            System.out.println("Error message: " + e.getMessage());
            return null; 
        }

        return item;
    }
}

Now if I were to initialise an ImmutableList of type MutableObject, this does not prevent me from modifying a property of MutableObject. As in:

 class MutableObject{
    public int a;
}
        LinkedList<MutableObject> list = new LinkedList<MutableObject>();

        MutableObject object = new MutableObject();
        object.a = 0;

        list.add(object);

        ImmutableList<MutableObject> immutable_list = new ImmutableList<MutableObject>(list);

        System.out.println("Before:" +  immutable_list.get(0).a); //prints 0, as expected

        immutable_list.get(0).a = 1;
        System.out.println("After:" + immutable_list.get(0).a);//prints 1 - expecting 0

I have tried setting the method get to final, but to no avail.

It seems like I might have overlooked something in my implementation. How can I truly ensure immutability of the list, allowing the object itself to stay Mutable?

drew181
  • 333
  • 1
  • 10
  • 3
    "How can I truly ensure immutability of the list, allowing the object itself to stay Mutable?" - you can't. Either you make the objects in the list immutable themselves or not, all depending on your use-case. – Smutje Dec 23 '19 at 09:56
  • 1
    For other people on SO: note that making a collection `final` will not make the contained objects immutable, it is only the collection that cannot be reassigned. The same is true if you have an object containing other objects, for example a Date object still has setters, in that case use getters that return copies of the date or use a final `long` millis instead. – Christophe Roussy Dec 23 '19 at 10:13
  • Use [`Collections.unmodifiableList()`](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#unmodifiableList-java.util.List-) for an immutable list (unless it's homework). – Matthieu Dec 23 '19 at 10:20
  • @Matthieu: That doesn't do anything about the list referring to mutable objects. – Jon Skeet Dec 23 '19 at 10:21
  • @JonSkeet of course, you beat my edit ;) It just saves writing and debugging a new class. With regards to making a generic `` object immutable, I'm not sure it's a good idea in general, if the provider of said class didn't mean it to be immutable (except if he just "forgot" immutability has many advantages). – Matthieu Dec 23 '19 at 10:25
  • 1
    @Matthieu: My point is that the OP is not looking for `Collections.unmodifiableList`. They're specifically asking about the element mutability. – Jon Skeet Dec 23 '19 at 10:26

1 Answers1

0

The reason of your problem is that the object returned by get() method is referencing the same object in your actual list. Therefore the changes made to it are applied to your actual list's object.

On the other hand, you cannot ensure immutability of list's contents, you can only ensure that their references are not modified, whereas their values may change.

If you truly want to preserve objects in list and avoid modifying list's contents after get(), I suggest to return a deep copy of an object in your method. It will return the same object with brand new reference, which will not be linked to your list.

There are several ways to do it, you can find more information in this question

Steyrix
  • 2,796
  • 1
  • 9
  • 23
  • By definition, should an Immutable List preserve the contained object's value, or only their reference? – drew181 Dec 23 '19 at 10:55
  • @drew181 By definition, an immutable list is a collection with constant number of elements, providing **read-only** access to them. Therefore, your list should preserve both: the references and the values, no modifications at all. Copying of list objects as `get()` returned value will not expose references in list and also will not expose access to modifiable fields of objects, since all changes will be applied to copies. – Steyrix Dec 23 '19 at 11:12
  • Thanks for your help and clarifications. I made use of serialization to conduct deep-copying. I do not like how objects have to implement serialization for this to work, but I prefer this over making use of external libraries. – drew181 Dec 23 '19 at 11:55
  • @Steyrix I disagree with your definition of an immutable list: it should give *read-only* access to its objects (i.e. no `add*/remove` methods but only `get`), but *cannot* prevent mutating any of its objects, as it's the object's responsibility to be (im)mutable, not the container. – Matthieu Dec 23 '19 at 16:24
  • @Matthieu I guess you are right, since I got a little bit confused over this question yesterday – Steyrix Dec 24 '19 at 12:20