Cra*_*lus 156 java collections immutability
从集合框架概述:
不支持修改操作(例如
add
,remove
和clear
)的集合称为不可修改.不可修改的集合是可修改的.另外保证
Collection
对象中没有可见变化的集合称为不可变.不可变的集合是可变的.
我无法理解这种区别.这里不可修改和不可变
的区别是什么?
Jon*_*eet 193
不可修改的集合通常是可修改集合的包装,其他代码可能仍然可以访问.所以,虽然你不能做任何更改,如果你只需要不可修改的集合的引用,你不能依靠内容不改变.
一个不可变的集合保证没有什么可以改变集合了.如果它包装了一个可修改的集合,它确保没有其他代码可以访问该可修改的集合.请注意,虽然没有代码可以更改集合包含引用的对象,但是对象本身可能仍然是可变的 - 创建不可变集合StringBuilder
并不会以某种方式"冻结"这些对象.
基本上,区别在于其他代码是否能够改变背后的集合.
Pra*_*ate 83
基本上unModifiable
Collection是一个视图,所以间接它仍然可以从其他一些可修改的引用中"修改".另外,由于它只是对另一个集合的只读视图,当源集合更改时,unModifiable Collection将始终显示最新值.
但是,immutable
Collection可以视为另一个集合的只读副本,不能修改.在这种情况下,当源集合发生更改时,不可变集合不会反映更改
这是一个可视化这种差异的测试用例.
@Test
public void testList() {
List<String> modifiableList = new ArrayList<String>();
modifiableList.add("a");
System.out.println("modifiableList:"+modifiableList);
System.out.println("--");
//unModifiableList
assertEquals(1, modifiableList.size());
List<String> unModifiableList=Collections.unmodifiableList(
modifiableList);
modifiableList.add("b");
boolean exceptionThrown=false;
try {
unModifiableList.add("b");
fail("add supported for unModifiableList!!");
} catch (UnsupportedOperationException e) {
exceptionThrown=true;
System.out.println("unModifiableList.add() not supported");
}
assertTrue(exceptionThrown);
System.out.println("modifiableList:"+modifiableList);
System.out.println("unModifiableList:"+unModifiableList);
assertEquals(2, modifiableList.size());
assertEquals(2, unModifiableList.size());
System.out.println("--");
//immutableList
List<String> immutableList=Collections.unmodifiableList(
new ArrayList<String>(modifiableList));
modifiableList.add("c");
exceptionThrown=false;
try {
immutableList.add("c");
fail("add supported for immutableList!!");
} catch (UnsupportedOperationException e) {
exceptionThrown=true;
System.out.println("immutableList.add() not supported");
}
assertTrue(exceptionThrown);
System.out.println("modifiableList:"+modifiableList);
System.out.println("unModifiableList:"+unModifiableList);
System.out.println("immutableList:"+immutableList);
System.out.println("--");
assertEquals(3, modifiableList.size());
assertEquals(3, unModifiableList.size());
assertEquals(2, immutableList.size());
}
Run Code Online (Sandbox Code Playgroud)
产量
modifiableList:[a]
--
unModifiableList.add() not supported
modifiableList:[a, b]
unModifiableList:[a, b]
--
immutableList.add() not supported
modifiableList:[a, b, c]
unModifiableList:[a, b, c]
immutableList:[a, b]
--
Run Code Online (Sandbox Code Playgroud)
Mic*_*urr 11
我认为主要区别在于可变集合的所有者可能希望提供对其他代码的集合访问,但是通过不允许其他代码修改集合的接口提供该访问(同时保留该功能)拥有代码).因此集合不是不可变的,但某些用户不允许更改集合.
Oracle的Java Collection Wrapper教程有这样的说法(重点补充):
不可修改的包装有两个主要用途,如下所示:
- 在构建集合后使集合不可变.在这种情况下,最好不要维护对支持集合的引用.这绝对保证了不变性.
- 允许某些客户端以只读方式访问您的数据结构.您保留对支持集合的引用,但分发对包装器的引用.通过这种方式,客户可以查看但不能修改,同时保持完全访问权限.
// 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);
Run Code Online (Sandbox Code Playgroud)
输出:
[1, 2, 3]
[1, 2, 3]
[1]
Run Code Online (Sandbox Code Playgroud)
如果一个对象的状态在构造后不能改变,则该对象被认为是不可变的。创建集合的不可变实例后,只要对它的引用存在,它就会保存相同的数据。
\n不可变集合的优点之一是它自动是线程安全的。包含不可变对象的集合在构造后自动成为线程安全的。创建这样的集合后,您可以将其交给多个线程,它们都将看到一致的视图。
\n但是,不可变对象集合与不可变对象集合不同。如果包含的元素是可变的,则可能会导致集合行为不一致或使其内容看起来发生了变化。
\n简而言之,如果你给可变的东西添加一点不变性,你就会得到可变性。如果你给不可变的东西添加一点可变性,你就会得到可变性。
\n不可变和不可修改是不一样的:
\n不可变集合的行为方式与 Collections.unmodifying... 包装器相同。但是,这些集合不是包装器 \xe2\x80\x94,它们是由类实现的数据结构,其中任何修改数据的尝试都会导致引发异常。
\n如果您创建一个 List 并将其传递给 Collections.unmodifyingList 方法,那么您将获得一个不可修改的视图。底层列表仍然是可修改的,并且对它的修改可以通过返回的 List 可见,因此它实际上并不是不可变的。
\n要演示此行为,请创建一个 List 并将其传递给 Collections.unmodifyingList。如果您尝试直接添加到该不可修改的列表,则会抛出 UnsupportedOperationException。
\n但是,如果更改原始List,则不会产生错误,并且不可修改的List已被修改。
\n在这种情况下,要使集合在构建后不可变,最好不要维护对后备集合的引用。这绝对保证了不变性。
\n此外,允许某些客户端对您的数据结构进行只读访问。您可以保留对支持集合的引用,但分发对包装器的引用。这样,客户端可以查看但不能修改,而您则保持完全访问权限。
\n因此,不可变集合可以包含可变对象,如果包含可变对象,则该集合既不是不可变的,也不是线程安全的。
\n