Java Immutable Collections
Collection<String> c1 = new ArrayList<String>();
c1.add("foo");
Collection<String> c2 = Collections.unmodifiableList(c1);
c1
is mutable (i.e. neither unmodifiable nor immutable).c2
is unmodifiable: it can't be changed itself, but if later on I change c1
then that change will be visible in c2
.
This is because c2
is simply a wrapper around c1
and not really an independent copy. Guava provides the ImmutableList
interface and some implementations. Those work by actually creating a copy of the input (unless the input is an immutable collection on its own).
Regarding your second question:
The mutability/immutability of a collection does not depend on the mutability/immutability of the objects contained therein. Modifying an object contained in a collection does not count as a "modification of the collection" for this description. Of course if you need a immutable collection, you usually also want it to contain immutable objects.
Unmodifiable collections are usually read-only views (wrappers) of other collections. You can't add, remove or clear them, but the underlying collection can change.
Immutable collections can't be changed at all - they don't wrap another collection - they have their own elements.
Here's a quote from guava's ImmutableList
Unlike
Collections.unmodifiableList(java.util.List<? extends T>)
, which is a view of a separate collection that can still change, an instance ofImmutableList
contains its own private data and will never change.
So, basically, in order to get an immutable collection out of a mutable one, you have to copy its elements to the new collection, and disallow all operations.
The difference is that you can't have a reference to an immutable collection which allows changes. Unmodifiable collections are unmodifiable through that reference, but some other object may point to the same data through which it can be changed.
e.g.
List<String> strings = new ArrayList<String>();
List<String> unmodifiable = Collections.unmodifiableList(strings);
unmodifiable.add("New string"); // will fail at runtime
strings.add("Aha!"); // will succeed
System.out.println(unmodifiable);