内部是基于大小可变的数组实现的,内部的元素通过get,set进行操作和访问。
优点:
其优点就是数组的优点,能够实现对元素的快速随机访问
缺点:
缺点也是基于数组的特点,每个元素对应的内存地址是连续的,当数组大小满足时,需要增加存储能力,要将原有的数组中的数据复制到新的数组中。在插入、删除元素时,也要对应地对数组中的元素进行复制,移动代价较高
适合:
随机查找和遍历,不适合插入和删除
初始容量:
jdk1.7之前:初始容量为10
jdk1.7及之后:初始化为一个空数组。当存入第一个元素时,会触发懒加载机制(节省内存),使得容量变为10
扩容机制:
1. 检查新增元素后是否会超过数组的容量,若是,进行扩容操作
2. 设置新的容量为原来容量的1.5倍,集合元素数量上限为2^31-1
3. (这一步才是真正扩容操作)申请一个容量为原数组容量1.5倍的新数组,并将老数组中的元素复制到新数组中,完成扩容
4. 加入新增元素
是否线程安全:
黄色框中的操作不是一个原子操作,他是分两步构成的
由于不是原子操作,所以在多线程环境下执行的时候,这个操作便可能会被拆分。被拆分就有可能出现,一个线程忘某一数组单元中添加的值覆盖了另一个线程往此单元中添加的值。例子如下:
ArrayList如何保证线程安全:
在并发场景下,可以使用Collections.synchronizedList与CopyOnWriteArrayList来替代ArrayList。
其中Collections.synchronizedList在更新操作的时候使用了互斥锁的方式封装了内部方法。
CopyOnWriteArrayList在更新的操作中先加上了可重入锁,再使用数组复制的方法,将当前添加元素添加到新数组尾部。
对于写操作,明显使用Collections.synchronizedList比使用CopyOnWriteArrayList的速度快。但对于读操作,使用 CopyOnWriteArrayList的速度更快,并发性更好。
ArrayList的SubList方法:
subList方法并没有重新创建一个新的List,而是使用了原List的视图,这个视图使用内部类SubList表示。所以不能将subList方法返回的List强制转化为ArrayList等类,因为没有继承关系。
若涉及到对原List和subList的修改,还需注意:
1. 对父子List所做的非结构性修改(修改某个元素的值),都会影响到彼此
2. 对子List做结构性修改(在集合中增加或删除元素),会映射到父List上
3. 对父List做结构性修改,会抛出异常
ArrayList的序列化如何实现:
ArrayList底层是一个Object数组,它被transient关键字进行修饰了,这意味着它在默认的序列化策略中并没有序列化底层数组。通过重写了writeObject和readObject来实现序列化操作。
这是为了防止造成空间浪费,防止序列化的时候把多个null元素同时进行序列化。