【问题标题】:How to get a immutable collection from java HashMap?如何从 java HashMap 获取不可变集合?
【发布时间】:2012-02-21 00:43:23
【问题描述】:

我需要从 java HashMap 中获取一个集合,而不需要稍后在集合中反映映射中的更改。我想使用 Collection.toArray() 来实现这一点,但它不起作用。结果 Object[] 也在发生变化(javadocs 说返回的数组将是“安全的”,因为此集合不维护对它的引用)。有什么简单的方法可以实现吗?

【问题讨论】:

  • 我没有清楚地理解你想要达到的目标。但是 LinkedHashMap 是你要找的吗?
  • No..插入的顺序不是我想要的。假设我们有 的 HashMap。 Hashmap.values() 会返回一个 collection 。现在 HashMap 中的任何更改都反映在此集合中,这是默认行为。但是,我需要一个固定的集合,其中地图中的任何更改都不会是反映
  • @sanre6 你的意思是对 items(对象)的更改包含 HashMap,是偶然的吗?

标签: java collections hashmap


【解决方案1】:

通过单个 API 调用无法做到这一点,您需要使用深度克隆。更改原始文件时不会更改克隆文件。这个话题之前在 SO 上讨论过,见How to clone ArrayList and also clone its contents?Deep clone utility recomendation

【讨论】:

  • 我认为这个答案可以扩展:“深度克隆”是什么意思,这如何防止修改或“共享引用”?链接可能有用...
  • Cloner api 为我完成了这项工作。感谢您的链接
【解决方案2】:

【讨论】:

  • 然而,这并没有说明 包含 对象的可变性。
  • 我相信谷歌集合不可变地图是 OP 正在寻找的。 @pst:我对文档的阅读使我相信 com.google.common.collect.ImmutableMap 中包含的对象是不可变的。
  • @JustinMuller 我不相信它的解释是正确的。它没有说明 K 的不变性(在 Java 中实现这一点的唯一方法是添加 K 类型对象的副本/克隆)。它认为它与unmodifiableMap 不同——这将引发put 的异常——但仍将通过keys 显示新键(例如)如果original i> (backing) Map 被修改;文档听起来像是 the 的区别。
  • 如果原始支持映射被修改(例如通过 put),那么 ImmutableMap 副本将不会反映新的更改。 (如果 K 代表一个可变类型,那么你已经在做一些非常非常错误的事情了。)
  • 请注意,此答案链接到“google-collections”项目,该项目已于 2 多年前被放弃。见guava-libraries.googlecode.com
【解决方案3】:

您可以创建一个不可修改的Map

【讨论】:

  • 然而,这并没有说明 包含 对象的可变性。
  • 更不用说原图的变化反映在副本中了。
  • 我相信贾斯汀是对的。 unmodifiableMap 方法将返回映射的只读视图,该视图将反映对基本容器的任何更改,并且 sanre6 没有指定包含的对象应该是不可变的,只有映射应该是。
【解决方案4】:

以下内容仍然有效并描述了观察到的问题(请参阅有关执行何种复制的位)。但是,我没有提供任何关于如何执行深拷贝的答案。

相反,我的建议是将对象设计为immutable,这完全避免了这个问题。根据我的经验,这对于大多数琐碎的对象(即不是“容器”的对象)非常有效,并且可以简化代码和推理。


来自HashMap.values 的 Javadoc:

返回此映射中包含的值的集合视图。 集合由地图支持,因此地图的更改会反映在集合中,反之亦然...

也许创建一个副本会有所帮助?

HashMap<K,V> map = ....;
List<V> values = new ArrayList<V>(map.values());

本质上,它执行“现在分离”的shallow-copy。但是,作为浅拷贝,不会执行所包含对象的克隆/拷贝。 (如果需要 deep-copy 语义,请参阅 βнɛƨн Ǥʋяʋиɢ 的回答:问题本身在这件事上似乎有点模糊。)

愉快的编码

【讨论】:

  • 我也这样做了,这不起作用。这些变化也反映在新列表中
  • @sanre6 “更改”是指“更改对象集合中”吗? (与“更改集合”相反。)如果是这样,请参阅浅/深副本的链接,这些链接解释了观察到的行为,以及来自 βнɛƨн Ǥʋяʋиɢ 的答案。
  • 是的,完全改变了包含的对象
  • @sanre6 查看链接。然后是βнɛƨн Ǥʋяʋиɢ的回答。 :-)
  • @sanre6 我会亲自通过合同使对象本身不可变。移除对象的可变性可以完全否定这样的问题:不需要复制,因为你不能改变它。这对于“简单对象”非常有效
【解决方案5】:

使用HashMap.clone() 创建原始地图的浅表副本,然后从中检索值集合。这将在clone() 调用时创建对原始地图中对象的新引用;显然,包含的对象本身内部的更改仍将反映在复制的集合中。如果你想要这种行为,你唯一的方法就是硬拷贝你想要的集合中的地图对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 2010-11-25
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 2015-12-20
    相关资源
    最近更新 更多