Just because the reference to the list is immutable doesn't mean that the list it refers to is immutable.
Even if list
was made final
this would be allowed
// changing the object which list refers to
example.getList().add("stuff");
but this would not allowed:
// changing list
example.list = new ArrayList<String>(); // assuming list is public
In order to make the list immutable (prevent also the first line), I suggest you use Collections.unmodifiableList
:
public class Example {
final private ArrayList<String> list;
Example(ArrayList<String> listArg) {
list = Collections.unmodifiableList(listArg);
}
}
(Note that this creates an unmodifiable view of the list. If someone is holding on to the original reference, then the list can still be modified through that.)
With a String this behaviour isnt possible. So what is the difference here?
That is because a String
is already immutable (unmodifiable) just as the list would be if you turned it into an unmodifiableList.
Comparison:
String data structure | List data structure
.-------------------------+------------------------------------.
Immutable | String | Collection.unmodifiableList(...) |
-----------+-------------------------+------------------------------------|
Mutable | StringBuffer | ArrayList |
'-------------------------+------------------------------------'
Collections.unmodifiableList()
returns an immutable WRAPPER for given list. If I am correct, above will not guarantee immutability. A class may instantiate a list, instantiate Example, and can still modify the list that Example is holding by modifying the original list passed to the constructor. Albeit the answer may suffice to address the differences, it may fail to meet strict "immutability" requirements. – Eradis