3

我有一个关于不可变集合的一般性问题。我将使用 Java 作为我最了解的参考语言。

首先,是否有确保不变性的通用方法?我的意思是是否应该复制整个集合,进行更改然后返回新对象?有没有更复杂、更通用的方法?

更进一步,“明显的”(对我而言)可变集合(例如树)呢?通常它们被实现为具有 N 个子节点的节点。在这种情况下,您将如何保证不变性?递归地克隆和复制所有引用?

根据上述内容,我想知道这些集合的最佳方法是什么:

  1. 列表 - 基于数组的列表,我们会在进行更改之前复制它吗?
  2. 队列 - 前后两个数组,在返回之前克隆?那么基于波特的实现呢?
  3. 树木
  4. Hashmap - 复制桶数组,以及所有的冲突列表?

非常感谢您的回复。

4

4 回答 4

6

令人高兴的是,已经为您完成了大部分工作,请查看具有ImmutableCollectionImmutableListImmutableSetImmutableMap等的google guava 。

通过防止这些类的子类(通过使它们成为最终的,或使它们的构造函数私有)来确保不变性。

当您从可变集合创建不可变集合时,将复制可变集合中的数据,然后不允许所有突变操作 - 它们将引发异常(UnsupportedOperationException例如)。

出于性能原因,如果不需要,guava 库会尽量不复制数据。例如,如果您已经有一个ImmutableMap, 并用 新建一个ImmutableMap.copyOf(theOtherImmutableMap),则不会复制任何数据,因为我们已经知道另一个映射是不可变的,因此可以对同一数据进行两次引用。

于 2012-04-04T14:42:40.903 回答
2

就 Java 而言,Collections 实用程序类是您的朋友。我建议不要手动执行这些操作,而是使用给定的 API。特别注意不可变和不可修改的方法。

例如,就不可变而言,有:

<T> List<T>
emptyList() 
          Returns the empty list (immutable).
static
<K,V> Map<K,V>
emptyMap() 
          Returns the empty map (immutable).
static
<T> Set<T>
emptySet() 
          Returns the empty set (immutable).

对于不可修改的,您有:

static
<T> Collection<T>
unmodifiableCollection(Collection<? extends T> c) 
          Returns an unmodifiable view of the specified collection.
static
<T> List<T>
unmodifiableList(List<? extends T> list) 
          Returns an unmodifiable view of the specified list.
static
<K,V> Map<K,V>
unmodifiableMap(Map<? extends K,? extends V> m) 
          Returns an unmodifiable view of the specified map.
static
<T> Set<T>
unmodifiableSet(Set<? extends T> s) 
          Returns an unmodifiable view of the specified set.
static
<K,V> SortedMap<K,V>
unmodifiableSortedMap(SortedMap<K,? extends V> m) 
          Returns an unmodifiable view of the specified sorted map.
static
<T> SortedSet<T>
unmodifiableSortedSet(SortedSet<T> s) 

您可以在下面实施其他策略和一些策略,但我将从那里开始。

于 2012-04-04T14:46:56.023 回答
0

我假设您的意图是了解不可变集合如何在函数式语言(如 haskell 等)的框架内工作。这个想法是所有集合都是不可变的和最终的,从而避免了关于可变性、同步等的所有多线程陷阱,但仍然允许您添加、删除和修改,就好像它们是可变的一样

我见过的最好的例子是Clojure的源代码。它是一种类似于 lisp 的语言,因此将不可变集合作为核心特性来处理。我强烈建议您查看如何在 clojure 中实现集合,因为它们一定会回答您的许多问题。可能有些事情太复杂了(我仍然几乎不理解try)。看到这里,祝你好运

于 2012-04-04T15:29:57.720 回答
0

Clojure 包含这样的不可变(或持久)集合

它提供了您所追求的所有集合,并支持通过构造进行突变:简单地说,添加或删除新元素会返回一个新集合,通常通过巧妙使用 Trie 类型的数据结构重用旧集合的大部分.

就其本身而言,它们不适合在纯 Java 中使用——它们被设计为在 Clojure 中使用。

Pure4j尝试将这些(以及 Clojure 提倡的基于不可变/基于值的风格)移植到 Java 语言。这可能是你所追求的。

免责声明:我是 Pure4J 的开发者

于 2015-11-06T14:12:01.123 回答