从集合框架概述:

不支持修改操作(如添加、删除和清除)的集合被称为不可修改的。不是不可修改的集合是可修改的。 另外保证Collection对象中的任何更改都不可见的集合称为不可变集合。不是不可变的集合是可变的。

我不明白其中的区别。 这里unmodifiable和immutable的区别是什么?


当前回答

不可修改的集合通常是其他代码仍然可以访问的可修改集合的包装器。因此,如果您仅拥有对不可修改集合的引用,则不能对其进行任何更改,但不能指望内容不会更改。

不可变集合保证没有任何东西可以再改变集合。如果它包装了一个可修改的集合,它将确保没有其他代码可以访问该可修改的集合。注意,尽管没有代码可以改变集合包含引用的对象,但对象本身仍然可能是可变的——创建一个不可变的StringBuilder集合并不会以某种方式“冻结”那些对象。

基本上,区别在于其他代码是否能够在您背后更改集合。

其他回答

    // normal list
    List list1 = new ArrayList();
    list1.add(1);

    // unmodifiable list
    List list2 = Collections.unmodifiableList(list1);

    // immutable list
    List list3 = Collections.unmodifiableList(new ArrayList<>(list1));

    list1.add(2);
    list1.add(3);

    System.out.println(list1);
    System.out.println(list2);
    System.out.println(list3);

输出:

[1, 2, 3]
[1, 2, 3]
[1]

一个对象被认为是不可变的,如果它的状态在被构造后不能改变。创建集合的不可变实例后,只要对它的引用存在,它就会保存相同的数据。

不可变集合的一个优点是它是自动线程安全的。包含不可变对象的集合在构造后自动是线程安全的。创建这样一个集合后,可以将它交给多个线程,它们都将看到一致的视图。

然而,不可变对象的集合并不等同于不可变对象的集合。如果所包含的元素是可变的,则可能导致集合的行为不一致或使其内容看起来发生了变化。

简单地说,如果你给可变的东西加上一点不变性,你就得到了可变性。如果你给不可变的东西加上一点可变性,你就得到了可变性。

不可变和不可修改不是一回事:

不可变集合的行为与collections .unmodifiable…包装器。然而,这些集合不是包装器——它们是由类实现的数据结构,任何修改数据的尝试都会引发异常。

如果您创建了一个List并将其传递给集合。unmodifiableelist方法,那么你会得到一个不可修改的视图。底层列表仍然是可修改的,通过返回的list可以看到对它的修改,因此它实际上不是不可变的。

要演示此行为,请创建一个List并将其传递给Collections.unmodifiableList。如果尝试直接添加到不可修改的列表,则抛出UnsupportedOperationException。

但是,如果您更改了原始List,则不会生成错误,并且不可修改的List已被修改。

在这种情况下,要使集合在构建后不可变,最好不要维护对支持集合的引用。这绝对保证了不变性。

此外,允许某些客户端只读访问您的数据结构。您可以保留对支持集合的引用,但可以分发对包装器的引用。通过这种方式,客户端可以查看但不能修改,而您保持完全访问权限。

因此,不可变集合可以包含可变对象,如果这样做,则该集合既不是不可变的,也不是线程安全的。

不可修改的集合通常是其他代码仍然可以访问的可修改集合的包装器。因此,如果您仅拥有对不可修改集合的引用,则不能对其进行任何更改,但不能指望内容不会更改。

不可变集合保证没有任何东西可以再改变集合。如果它包装了一个可修改的集合,它将确保没有其他代码可以访问该可修改的集合。注意,尽管没有代码可以改变集合包含引用的对象,但对象本身仍然可能是可变的——创建一个不可变的StringBuilder集合并不会以某种方式“冻结”那些对象。

基本上,区别在于其他代码是否能够在您背后更改集合。

如果我们讨论的是JDK不可修改*和番石榴不可修改*,实际上它们的区别还在于性能。如果不可变集合不是常规集合的包装器(JDK实现就是包装器),那么它们可以更快、更节省内存。 以番石榴团队为例:

JDK提供了集合。不可修改的xxx方法,但在我们看来,这些可以

<…>

低效:数据结构仍然有可变集合的所有开销,包括并发修改检查,哈希表中的额外空间等。

[不可更改和不可更改]

不可修改的集合(对象)仍然可以通过改变原始对象来改变。使用参考是可能的。

Java提供了几种方法来创建一个不可修改的映射:

Collections.unmodifiableMap () Java 9 Map.of(), Map.ofEntries()