问题
The java util Collections class offers to create an "unmodifiable" decorator around any existing list. But as we all know (or learn the hard way at some point); it is really just a decorator around the list that was originally passed into that call. The decorated list can't be changed; but it will change under the covers if the "original" list is modified.
Now assume that I have some class like
class Whatever {
private final List<IDontCare> someElements;
public Whatever(List<IDontCare> incomingElements) {
someElements = unmodifiableCopyOf(incomingElements);
That class simple wants to use a really unmodifiable copy of the incoming data. Nice idea - but it seems that there is no clean/generic way to implement that method unmodifiableCopyOf().
One could think of:
- use "clone()" to create a copy ... unfortunately, a "visible" clone() exists only on concrete implementations like ArrayList; but if I only know "it is something implementing List" ... well; I can't clone (nicely explained here)
- simply create an "intermediate container"; like new ArrayList(incomingElements) and have that "decorated"; but what if incomingElements was meant to be a linked list?
- Use some other library, like Guava that provides "A high-performance, immutable, random-access List implementation". But well, Guava is not an option at my place (we are pretty much restricted to our own libraries and some Apache commons stuff).
Tl;dr: is there really no "generic" solution (relying on "standard libraries") to this problem what gives me a truly un-modifiable collection; based on some other collection?
回答1:
option #1
public Whatever(List srcList) {
Constructor<? extends List> c = srcList.getClass().getConstructor(Collection.class);
someElements = unmodifiableList(c.newInstance(srcList));
Try-catch is omitted. This will work for lists from java.util, but no guarantees for custom lists.
option #2
public Whatever(ArrayList srcList) {
someElements = unmodifiableList(new ArrayList(srcList));
public Whatever(LinkedList srcList) {
someElements = unmodifiableList(new LinkedList(srcList));
public Whatever(List srcList) {
someElements = unmodifiableList(new ArrayList(srcList)); // ok, no info
Don't be tricked by this solution, if list reference passed to constructor is of type List, third constructor will be used.
回答2:
Is there a generic way to create an un-modifiable List/Set/Map from Collection/List/Set… ?
Yes! Use the Collections.unmodifiable...s.
Set<String> stuff = Collections.<String>unmodifiableSet(oldSet);
The decorated list can't be changed; but it will change under the covers if the "original" list is modified.
If you don't want that then the fault is in the handling of the original collection rather than the construction of the new one. You should take a copy of it at construct time.
Set<String> uset = Collections.<String>unmodifiableSet(new HashSet<>(oldSet));
来源:https://stackoverflow.com/questions/36747339/is-there-a-generic-way-to-create-an-un-modifiable-list-set-map-from-collection-l