静态初始化unmodifiableCollection.get保证不可变吗?

时间:2010-01-15 20:21:05

标签: java collections immutability

静态初始化unmodifiableCollection.get保证不可变吗?

有关:

静态最终地图FOO =   Collections.unmodifiableMap(new HashMap());

多个线程可以使用方法获取而不会遇到问题吗?

即使FOO中的项目无法添加/删除,什么阻止get方法操纵FOO的内部状态以进行缓存等。如果内部状态以任何方式被修改,则FOO不能同时使用。如果是这种情况,java中真正的不可变集合在哪里?

6 个答案:

答案 0 :(得分:4)

给出具体的例子:

static final Map FOO = Collections.unmodifiableMap(new HashMap());

然后FOO将是不可变的。它也永远不会有任何元素。鉴于更一般的情况:

static final Map BAR = Collections.unmodifiableMap(getMap());

然后,这是否是不可变的完全取决于其他人是否可以到达底层地图,以及它是什么类型的地图。例如,如果它是LinkedHashMap,则可以通过访问顺序修改基础链接列表,并且可以通过调用get()来更改。最安全的方法(使用非并发类)可以:

static final Map BAR = Collections.unmodifiableMap(new HashMap(getMap()));

javadocs for HashMap暗示只要你不对地图进行任何结构改变,那么同时使用它是安全的,所以对于你可以使用的任何访问器来说这应该是安全的,即各种集合并迭代它们和get()应该是安全的。

如果您可以使用并发类,那么您也可以这样做:

static final Map BAR = Collections.unmodifiableMap(new ConcurrentHashMap(getMap());

这将明确安全地从多个线程使用,因为ConcurrentHashMap显然是多线程访问安全的。内部状态可能是可变的,但外部可见状态不会,并且因为类保证是线程安全的,所以我们可以安全地认为它是外部不可变的。

答案 1 :(得分:2)

冒着听起来像我正在广告狂欢的风险,请使用Google Immutable Collections并完成它。

答案 2 :(得分:0)

Java SDK中没有真正的不可变映射。所有建议的Chris地图都只是线程安全的。不可修改的Map也不是不可变的,因为如果基础Map发生了变化,那么ConcurrentModificationException也会出现。{/ p>

如果您想要真正不可变的地图,请使用Google Collections / Guava中的ImmutableMap。

答案 3 :(得分:0)

其实是个好问题。想想WeakHashMap - 可以在没有调用变异操作的情况下进行更改。访问顺序模式中的LinkedHashMap大致相同。

HashMap州的API文档:

  

请注意,此实现不是   synchronized。如果有多个线程   同时访问哈希映射,并在   至少有一个线程修改了   在结构上映射,它必须是   外部同步。 (结构性的   修改是任何操作   添加或删除一个或多个映射;   只是改变相关的价值   用一个实例已经的密钥   包含不是结构   修改。)

据推测,那应该是当且仅当。这意味着如果get“实际上是不可变的”,则HashMap不需要同步。

答案 4 :(得分:-1)

我建议任何线程操作使用ConcurrentHashMap或HashTable,两者都是线程安全的。

答案 5 :(得分:-1)

只要对象遵守其合同(即无法修改的地图),返回的地图上的吸气剂是否恰好与某种内部状态混合是不重要的。所以你的问题是“咆哮错误的树”。

如果您对所包含的地图没有所有权和控制权,那么您对UnmodifiableMap持谨慎态度是正确的。例如

Map<String,String> wrapped = new HashMap<String,String>();
wrapped.add("pig","oink");
Map<String,String> wrapper = Collections.unmodifiableMap(wrapped);
System.out.println(wrapper.size());
wrapper.put("cow", "moo"); // throws exception
wrapped.put("cow", "moo");
System.out.println(wrapper.size()); // d'oh!
相关问题