前言
知识点概览:
-
容器中的设计模式
-
从Arrays.asList() 看集合与数组的关系
-
集合世界中的 fail-fast 机制
- 什么是 fail-fast 机制
- ArrayList.sublist() 有什么坑?
- foreach 循环里为什么不能进行元素的 remove/add 操作?
-
集合世界中的 fail-safe 机制
- copy-on-write 机制
-
CopyOnWriteArrayList
- 关键知识点
- 读写操作
- 遍历 - COWIterator
- 缺点 和 使用时需要注意的点
- 提问
容器中的设计模式
1.迭代器模式
迭代器模式指的就是 提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示,为遍历不同的聚合结构提供一个统一的接口。
- Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
- 从 JDK 1.5 之后可以使用foreach 方法来遍历实现了 Iterable 接口的聚合对象。
2. 适配器模式
适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
Arrays.asList(T... a)
体现的就是适配器模式。
拿生活中的例子作比方:我很早以前用的是3.5mm耳机孔的耳机,后面我换手机了,只能用type-c的耳机,通过type-c转接头我以前的耳机还是能用,这里面就用了适配器模式;在上面的例子中,入参数组就是3. 5mm耳机,Arrays.asList()
这整个方法就是起到适配器type-c转接头的作用,List就是支持我type-c口的耳机。
从 Arrays.asList() 看集合与数组的关系(内含坑)
数组与集合都是用来存储对象的容器,前者性质单一、简单易用;后者类型安全,功能强大,而两者之间必然有相互转换的方式。
由于两者的特性存在很大的差别,所以在转换过程当中,如果不去详细了解背后的转换方式,很容易产生意料之外的问题。
在数组转集合的过程中,需要注意是否使用了视图方式。
这里说的视图,指的就是一个具有限制的集合对象,只是把原有数据展现出来给你看,例如不可更改视图,子视图等等,这些视图对于原对象具有不同的操作权限。
以 Arrays.asList()
为例,它把数组转成集合时,不能修改其修改集合相关的内容。它的add/remove/clear
方法会抛出UnsupportedOperationException
。
上述代码可以证明可以通过set
方法修改元素的值,原有数组相应位置的值同时也会被修改,但是不能进行修改元素个数的任何操作,否则就会抛异常。
有的人可能就会问了,返回的是ArrayList类,为什么不能对这个集合进行修改呢?
因为这个ArrayList并不是我们平常使用的ArrayList类,这里是个冒牌货,是Arrays工具类中的一个内部类而已。
这个类非常的简单,仅提供了改和查相关方法的实现,让我们来看一下:
至于增删的操作会抛出会抛出UnsupportedOperationException
,是在这个假类的父类AbstractList中实现的
所以当你的业务场景中,数组转成集合之后,如果可能会对集合进行增和删的操作,请使用真ArrayList来创建一个新集合。
List<Object> list = new java.util.