繁体   English   中英

返回不可修改的地图

[英]Returning unmodifiable map

我有一个地图,如下所示:

Map<String,Map<String,Object>>

给定一把钥匙,我将被退回地图。
建议使用什么方法使返回的Map不可变。
这实质上意味着:
地图是不可变的(无编辑/删除/添加)
底层对象是不可变的(无编辑)

我们没有使Object不变的选择。

您要做的是对返回的Map进行深层复制。

Java HashMap-深层副本

您可以使每个地图不可修改,然后使整个地图不可修改。

public Map<String,Map<String,Object>> makeUnModifiable(Map<String,Map<String,Object>> a){
  for(Entry<String, Map<String, Object>> e:a.entrySet()){
    e.setValue(Collections.unmodifiableMap(e.getValue()));
  }
  return Collections.unmodifiableMap(a);
}

真正的问题是您仍然提供对地图中值的访问。 您可以创建这些对象的副本,但这不能解决问题。 使对象类不可变,或为它们创建一个Wrapper类,以禁用setter方法。

您可以通过扩展AbstractMap来制作一个其地图值也无法修改的不可修改地图。

要实现不可修改的地图,程序员只需扩展此类并为entrySet方法提供实现,该方法将返回地图映射的set-view。 通常,返回的集合将依次在AbstractSet之上实现。 该集合不支持addremove方法,并且其迭代器不支持remove方法。

package mcve;

import java.util.*;

public final class UnmodifiableMapOfMaps<K, L, V> extends AbstractMap<K, Map<L, V>> {
    // Optionally Map<? extends K, ? extends Map<? extends L, ? extends V>>
    // but it would make the code a lot more difficult to read.
    private final Map<K, Map<L, V>> map;

    public UnmodifiableMapOfMaps(Map<K, Map<L, V>> map) {
        this.map = Objects.requireNonNull(map);
    }

    // Additionally override size(), get(), etc., entirely optionally.
    // Doing so would merely be an optimization since AbstractMap
    // implements those methods via the entrySet() iterator.

    @Override
    public Set<Entry<K, Map<L, V>>> entrySet() {
        return new AbstractSet<Entry<K, Map<L, V>>>() {
            @Override
            public int size() {
                return map.size();
            }

            @Override
            public Iterator<Entry<K, Map<L, V>>> iterator() {
                return new Iterator<Entry<K, Map<L, V>>>() {
                    private final Iterator<Entry<K, Map<L, V>>> it = map.entrySet().iterator();

                    @Override
                    public boolean hasNext() {
                        return it.hasNext();
                    }

                    @Override
                    public Entry<K, Map<L, V>> next() {
                        // Return the Entry as an immutable Entry with an
                        // unmodifiableMap as the value.
                        Entry<K, Map<L, V>> entry = it.next();
                        K         key = entry.getKey();
                        Map<L, V> val = Collections.unmodifiableMap(entry.getValue());
                        return new SimpleImmutableEntry<>(key, val);
                    }
                };
            }
        };
    }
}

抽象集合确实是非常好的类,因为它们会产生很多这样的问题,这些问题相当容易解决,而无需从头开始编写新容器。

除了编写不可变对象之外,没有其他方法可以用Java制作不可变对象。 Java没有像C ++中的const这样的功能。

在不实际实例化新对象的情况下执行此操作的一种方法是按如下方式编写接口,然后在您不想公开setter的任何时候返回ImmutableFoo

interface ImmutableFoo {
    int getValue();
}
interface MutableFoo extends ImmutableFoo {
    void setValue(int value);
}
class Foo implements MutableFoo {
    private int value;
    public Foo(int value)                     { this.value = value; }
    @Override public int  getValue()          { return value;       }
    @Override public void setValue(int value) { this.value = value; }
}

否则,如果Foo是您无法更改的类,则必须编写类似以下内容:

class FooAccessor {
    private final Foo foo;
    public FooAccessor(Foo foo) { this.foo = Objects.requireNonNull(foo); }
    public int getValue()       { return foo.getValue(); }
}

例如,可以与不可修改的AbstractMap示例结合使用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM