浅学ArrayList
目录
ArrayList
ArrayList就是一个动态数组,底层的实现是Array。相比于普通的数组,Array没有固定大小的限制,我们可以添加或者删除元素,ArrayList继承了 AbstractList ,并实现了 List 接口。
ArrayList创建
如果调用的是无参构造来创建ArrayList,那么创建的数组大小为0,如果调用的是有参构造来创建,那么数组大小为指定的数组大小。并且无论是有参创建还是无参创建,它允许任何元素插入,包括null。
ArrayList扩容机制
- ArrayList()会使用长度为0的数组
- ArrayList(int initialCapacity)会使用指定容量的数组
- public ArrayList(Collention <? extends E> c)会使用c的大小作为数组容量
- add(Object o)首次扩容为10,再次扩容为上次的1.5倍
- addAll(Collection c)没有元素时,扩容为Math.max(10,实际元素个数),有元素时为Math.max(原容量1.5倍,实际元素个数)
使用add方法添加数据时,触发扩容机制
如果使用的是无参构造来创建,则在第一次添加的时候数组会进行扩容,扩容后的数组长度为10。
如果使用的是有参构造来创建,在数组存满后,下一次再使用add方法添加元素时候,则数组会触发ArrayList的自动扩容机制,此时数组容量扩大为原来的1.5倍。此处的1.5倍并不是使用乘法或者除法来计算扩容后的容量的,而是采用的右移一位来得出一半的容量,然后再加上原始容量得出扩容后数组的容量。
*add方法触发扩容*
例如原来数组容量为15
现在数组存满后进行扩容
第一步:15>>>1
-> 7
第二步:15+7
-> 22
使用addAll方法添加数据时,触发扩容机制
如果使用无参构造来创建,在第一次使用addAll方法添加元素时,触发扩容机制:
1、如果添加元素小于10,则扩容后数组容量为10。
2、如果添加元素大于10或者添加元素超出当前数组容量,则扩容的容量取决于下次扩容的大小和添加数组元素的大小取最大值为数组扩容后的容量大小。(有参构造的数组容量满后的扩容机制也是该条)。
ArratList特性
优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存中是连续存放的)
缺点:因为地址连续,ArrayList要移动数据,所以插入和删除操作效率比较低。
特性
- 允许插入的元素重复
- 插入的元素是有序的
- 动态扩容
- 非线程安全,异步
- 基于动态数组的数据结构
- 擅长随机访问(get set)
ArrayList适用场景分析
- 当需要对数据进行随机访问的时候选用
- 如果容量固定,并且只会添加到尾部,不会引起扩容,则优先采用
注意:
- 尽量避免扩容的发生,以及非顺序的插入。
- 如果add()方法添加到的是数组的尾部,并且增加的数据量很大,应该使用ensureCapacity()方法,该方法的作用是预先设置ArrayList的大小,这样可以提高初始化速度。
- 高并发的情况下,线程不安全。多个线程同时操作会引发不可预知的异常错误
- ArrayList实现了Cloneable接口,标识着它可以被复制,这里的clone()方法复制其实是浅复制
- ArrayList 实现了 java.io.Serializable 接口,这意味着 ArrayList 支持序列化,能通过序列化去传输。