问题
If I write
List<Integer> a1 = Arrays.asList(1, 2, 3);
List<Integer> a2 = Collections.unmodifiableList(a1);
a2
is read-only but if I write
a1.set(0,10);
then a2
is also modified.
If in the API is said:
Returns an unmodifiable view of the specified collection. This method allows modules to provide users with "read-only" access to internal collections.
then, why if I modify the original collection also the target-copied collection is modified?
Maybe did I misunderstand the meaning and if so what's the way to write a defensive copy of that collection?
回答1:
Yes, you understood it correctly. The idea is that the object returned by umodifiableCollection
can't directly be changed, but could change through other means (effectively by changing the internal collection directly).
As long as something has access to the internal list, the "unmodifiable" collection could be changed.
That's why you usually construct a unmodifiable collection and make sure that nothing can ever get to the internal list:
Collection<Integer> myUmodifiableCollection = Collection.umodifiableCollection(Arrays.asList(1, 2, 3));
Since nothing ever gets a reference to the List
created by asList
, this is a truly unmodifiable collection.
The advantage of this approach is that you don't need to copy the original collection/list at all, which avoids using memory and computing power.
Guava provides the ImmutableCollection class (and its subclasses such as ImmutableList) which provide true immutable collections (usually by copying the source).
回答2:
Maybe did I misunderstand the meaning and if so what's the way to write a defensive copy of that collection?
Typically, you would use it that way:
private List<Integer> a1 = Arrays.asList(1, 2, 3);
public List<Integer> getUnmodifiable() {
return Collections.unmodifiableList(a1);
}
Someone who calls getUnmodifiable
and does not have access to the internal of your class (i.e. they can't acces the private variable a1
), won't be able to modify the returned list.
回答3:
The idea is that you can't modify the list via a2
.
Modifying the a1
list will indeed modify what you see in a2
- this is intended.
Just dont have a public way to access the list a1
, and you should have what you want :)
回答4:
the API says it internal collections in your case the collection is not internal
the point is that when you have a private list in class an a gettet for that list, then you may want callers of the getter to not be able to modify the list in witch case you'll have to return an umodifiable list. otherwise the returned list is just a reference to your internal/private list and thus its content can be modified.
回答5:
The statement:
Collections.unmodifiableList(a1);
returns a wrapper over the original collection whose modifier methods throw UnsupportedOperationException
.
The wrapper is read-through, meaning that if you modify a1
, the changes reflect on the wrapped collection a2
.
回答6:
If you were looking to keep a1
mutable and make an immutable copy of it without Guava, this is one way you could do it.
List<Integer> a1 = Arrays.asList(1, 2, 3);
List<Integer> a2 = Collections.unmodifiableList(new ArrayList<>(a1));
回答7:
a1
and a2
will reference the same data (memory).
the un-mofifiable part comes , only with a2
as entry.
imaging if you are passing a2
to a method where you expect the method to be idempotent. such cases a2
helps.
in summary you cant modify data using a2
pointer.
回答8:
If you need unmodifiable and immutable list or in other words unmodifiable copy of the source list without any dependency to other libraries try this:
Collections.unmodifiableList(Collections.list(Collections.enumeration(sourceList)))
Collections.list()
copies values from its enumeration.
来源:https://stackoverflow.com/questions/15111073/collections-unmodifiablelist-and-defensive-copy