不可变集合实现

时间:2012-04-04 14:38:15

标签: java collections immutability

关于不可变集合,我有一个普遍的问题。我将使用Java作为参考实验室,因为我知道它最好。

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

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

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

  1. 列表 - 我们在进行更改之前会复制的基于数组的内容吗?
  2. 队列 - 前后两个数组,在返回前克隆?基于bode的实现怎么样?
  3. Hashmap - 复制存储桶数组以及所有碰撞列表吗?
  4. 非常感谢您的回复。

4 个答案:

答案 0 :(得分:6)

令人高兴的是,大部分内容已经为您完成,请查看google guava,其中包含ImmutableCollectionImmutableListImmutableSetImmutableMap等。

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

当你从一个可变集合中创建一个不可变集合时,会复制可变集合中的数据,然后不允许所有变异操作 - 它们将抛出异常(例如UnsupportedOperationException)。

出于性能原因,番石榴图书馆将尽力不复制数据,如果他们不需要的话。例如,如果您已经拥有ImmutableMap,并使用ImmutableMap.copyOf(theOtherImmutableMap)创建一个新的,则不会复制任何数据,因为我们已经知道其他地图是不可变的,所以可以拥有两个对同一数据的引用。

答案 1 :(得分: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) 

还有其他一些策略你可以在下面实现,但我会从那里开始。

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

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

就他们自己来说,这些不适合直接使用Java - 它们被设计用于Clojure。

Pure4j试图将这些(以及Clojure提倡的基于不可变/值的样式)移植到Java语言中。这可能是你追求的目标。

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