目录
一、ArrayList的扩容机制
1、ArrayList创建时的长度
(1)ArrayList()会是长度为0的数组
(2)ArrayList(int initialCapacity)会是指定容量的数组
(3)ArrayList(Collection<?extends E> c)会是以c的大小作为数组的大小
(4)add(Object o)首次扩容为10,再次扩容为之前容量的1.5倍
解释:
ArrayList按无参构造创建时大小为0,当第一次调用add方法时会扩容到10,我们继续调用add方法直至10个空位被添满,再次调用add方法时,有于没有空位了,此时开始扩容,将数组大小扩容到之前大小的1.5倍,即之前大小是10则扩容后大小为15,再次扩容为15*1.5,以此类推。
(5)addAll(Collection c)没有元素时,扩容为Math.max(10,实际元素个数),有元素时为Math.max(原容量的1.5倍,实际元素个数)
解释:
与add方法扩容方法类似,但又有一定区别,主要区别是,当调用addAll方法插入的大小大于空位大小时进行扩容,如果需要扩容的大小大于了原规则扩容的大小,则会以该扩容大小进行扩容:
简单的案例:
刚开始数组长度为0,调用addAll方法插入一个容量为11的集合,原本应该按照10来扩容的,但由于11>10,所以此时直接扩容到11,再次调用add方法插入一个容量为11*1.5+1的集合,此时又超过了原规则扩容的大小,又以11*1.5+1大小进行扩容。
简单来说,就是按照扩容规则中较大的那一个进行扩容,即Math.max(规则计算扩容大小,实际插入数据大小)
二、ArrayList和LinkedList对比
1、ArrayList的特性
(1)基于数组,需要连续内存
(2)随机访问快(根据下标访问)
(3)尾部插入、删除性能可以,其他部分插入、删除都会移动数据,因此性能会低
(4)优点:可以利用cpu缓存,局部性原理
2、LinkedList的特性
(1)基于双向链表,无需连续缓存
(2)随机访问慢(要沿着链表遍历)
(3)优点:头尾插入、删除性能高
(4)占用内存多
3、初步比较
ArrayList综合性能较高,建议多使用,适合情形:不须要频繁插入和删除数据到数组头部和前面部分,查询效率比LinkedList高。
LinkedList对于某些特定情况效率高,一般仅适合这些场景:需要频繁的插入、删除数组头部元素和前面部分时。对于中间部分的元素,由于其插入、删除前需要先遍历到该点,所以该情况下效率低于ArrayList,不推荐。
三、fail-fast与fail-safe
ArrayList是fail-fast的典型代表,遍历的同时不能修改,尽快失败。
CopyOnWriteArrayList是fail-safe的典型代表,遍历的同时可以修改,原理是读写分离。