本文已参与「新人创作礼」活动,一起开启掘金创作之路。
fail-fast机制
在集合中定义一个变量modCount来记录集合的修改次数,每次对集合结构的修改都通过modCount++来告知集合的操作者,尽可能的提示其他操作者当前集合被修改过了。如果 操作者认为集合被操作过对自己的逻辑有影响,那么则可以抛出ConcurrentModificationException异常。
常用的集合
-
Set
- HashSet : 基于HashMap的Set实现,其内部核心是
HashMap<E,Object>; - TreeSet : 基于TreeMap的NavigableSet实现,其内部核心是
TreeMap<E,Object>;
- HashSet : 基于HashMap的Set实现,其内部核心是
-
List
-
ArrayList
-
List接口的可变长数组实现。
-
允许空元素
-
get、set等操时间复杂度O(1)。add操作时间复制度O(n)
-
非线程安全的。多线程情况下需要加锁,如果么有外部锁,需要
Collections.synchronizedList用包裹起来。
List list = Collections.synchronizedList(new ArrayList(...));
-
默认初始长度是10。
-
最大长度是
Integer.MAX_VALUE;
-
-
LinkedList
- List接口的双向链表实现。
- 允许空元素。
- get、set操作时间复杂度是O(n),add操作时间复杂度是O(1)。
- 非线程安全。
-
-
Map
- HashMap
- TreeMap
HashMap数据结构?
HashMap在1.8中是由三个部分组成的,数组、链表、红黑树;
put、get方法的时间复杂度是O(1)~O(log(n))
HashMap的关键参数:
- 初始容量:默认16,必须是2的幂(因此在扩容的时候,每个bin中的元素要么保持在相同的索引上,要么在新表中以2的幂次移动。 总之一句话就是提高扩容效率 );
- 负载因子:默认0.75;
put操作:
表格扩容/初始化:
注意:扩容扩的是table.length,是数组的长度,不是HashMap的总容量,理论上讲HashMap没有容量上限。
- HashMap的初始化操作是在第一次put操作是进行的。
- 扩容是将容量扩大一倍
- 最大容量是 2^30
- 扩容后对所有元素进行rehash
使用hashmap的注意事项:
核心重点是减少rehash操作,也就是扩容操作。还有就是减少链表长度和红黑树深度,也就是所谓的哈希冲突。
-
在能预计到放入元素个数的情况下,初始化时就指定HashMap的容量和负载因子,initialCapacity=Math.ceil( N / loadFactor )。
放入元素个数N,初始化容量initialCapacity=Math.ceil( N / loadFactor ),譬如需要放入15个元素,使用负载因子0.75,那么初始化为 new HashMap(20,0.75);如果我们用new HashMap(15,0.75),那么hashMap在初始化的时候容量是16,当元素放入到12后,hashMap将触发扩容,即Rehash。
-
合理使用Key的hashcode方法,减少hash冲突。