简体   繁体   English

为什么不使用Collections类的不可修改方法来创建具有新元素的集合?

[英]Why don't the unmodifiable methods from Collections class, create collections with new elements?

Suppose there is this code: 假设有以下代码:

List<String> modifiableList = new ArrayList<String>(Arrays.asList("1","2","3"));
List<String> unmodifiableList = Collections.unmodifiableList(modifiableList);
System.out.println(unmodifiableList);
modifiableList.remove("1");
modifiableList.remove("3");
System.out.println(unmodifiableList);

it prints 它打印

[1, 2, 3]
[2]

If changing the second line to 如果将第二行更改为

List<String> unmodifiableList = Collections.unmodifiableList(
                                       new ArrayList<String>(modifiableList));

it works as expected. 它按预期工作。 The question is why doesn't the UnmodifiableList inner class from Collections (and all the other unmodifiable classes) from there create a fresh copy of the original list, as does the constructor of ArrayList for example in order to really make it unmodifiable? 问题是,为什么Collections的UnmodifiableList内部类(以及所有其他不可修改的类)为什么不创建原始列表的新副本,例如ArrayList的构造函数是否真的使其无法修改?

Edit: I understand what the code does; 编辑:我了解代码的作用; my question is why was it implemented this way? 我的问题是为什么以这种方式实施? Why does the constructor from the UnmodifiableList (inner class from Collections) behave like the constructor of ArrayList in creating a fresh copy of the underlying array? 为什么在创建基础数组的新副本时,UnmodifiableList(Collections的内部类)中的构造函数的行为类似于ArrayList的构造函数? Why a modifiable collection (ArrayList) copies the whole content while an unmodifiable collection doesn't? 为什么可修改的集合(ArrayList)复制整个内容,而不可修改的集合则不复制?

The reason is simple efficiency. 原因是效率简单。 Copying all of the elements of a collection could be very time-consuming, particularly if the collection being wrapped has some sort of magic going on like JPA lazy-loading, and requires extra memory. 复制集合中的所有元素可能会非常耗时,特别是如果要包装的集合具有某种不可思议的效果(例如JPA延迟加载),并且需要额外的内存。 Wrapping the underlying collection as-is is a trivial operation that imposes no additional overhead. 按原样包装基础集合是一项微不足道的操作,不会增加任何额外的开销。 In the case where the developer really does want a separate copy (unmodifiable or not), it's very easy to create it explicitly. 如果开发人员确实确实想要单独的副本(无论是否不可修改),则显式创建它非常容易。 (I tend to use Guava Immutable* for this.) (我倾向于为此使用番石榴Immutable* 。)

Well the purpose of the methods is to create an unmodifiable view on an existing collection. 这些方法的目的是在现有集合上创建不可修改的视图 That's the documented behaviour, and in many cases it's exactly what you want - it's much more efficient than copying all the data, for example... or you want to hand callers collections which will reflect any changes you want to make, but without allowing them to make changes. 这就是记录的行为,而且在许多情况下,这正是你想要的东西-它比复制所有数据,比如更有效的...或者你想手工调用者的集合,这反映要进行任何更改,但没有允许他们做出改变。

If you want an immutable copy of the data (or at least the references...) then just create a copy and then create an immutable view over the top of it - just as you are. 如果您想要数据的不可变副本 (或至少是引用...),则只需创建一个副本,然后在其顶部创建不可变视图即可,就像您一样。

So basically, you can easily create either a view or a copy-and-view, based on Collections.unmodifiable* themselves performing the view operation. 因此,基本上,您可以根据执行视图操作的Collections.unmodifiable*本身轻松地创建视图或复制视图。 So we have two orthogonal operations: 因此,我们有两个正交运算:

  • Create a copy (eg via the constructor) 创建一个副本(例如通过构造函数)
  • Create a view (via Collections.unmodifiable* ) 创建一个视图(通过Collections.unmodifiable*

Those operations can be composed very easily. 这些操作可以很容易地组成。 If Collections.unmodifiable* actually performed a "copy only" then we'd require other operations in order to just make a view. 如果Collections.unmodifiable*实际执行“复制唯一”,那么我们就需要为只是做一个视图等操作。 If you accept that both options are useful in different situations, making them composable gives lots of flexibility. 如果您接受这两个选项在不同情况下都是有用的,则使它们可组合可提供很大的灵活性。

Please note, that unmodifiableList returns a "unmodifiable view " of provided list. 请注意,unmodifiableList返回所提供列表的“ unmodifiable view ”。 So the list itself stays at it is (it can be still modified), only its "unmodifiable view" is unmodifiable. 因此,列表本身停留在该列表上(它仍然可以修改),只有其“不可修改的视图”是不可修改的。 You can think of it as of SQL tables and views --- you can run DML scripts on tables and it will be reflected on related views. 您可以将其视为SQL表和视图---您可以在表上运行DML脚本,并且它将反映在相关视图上。 As to ArrayList --- it's backed by... an array, so it's implementation feature, that it copies elements from provided source list (which doesn't have to be backed by an array actually). 至于ArrayList ---它由...支持,因此它是实现的功能,它从提供的源列表中复制元素(实际上不必由数组支持)。 Does it answer your question? 它能回答您的问题吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM