Collection接口
1、集合下的类图(该图简单描述结构,并不是完全正确的UML图)
2、ArrayList实现原理详解
1)概述
ArrayList是一个动态数组,其大小可变,且线程不安全。 ArrayList继承AbstractList抽象父类,实现了List接口(规定了List的操作规范)、RandomAccess(可随机访问)、Cloneable(可拷贝)、Serializable(可序列化)。
2)底层实现数据结构
ArrayList的底层是一个object数组,并且由trasient修饰
/**transient关键字表示ArrayList底层数组不会参与序列化,而是使用writeObject方法进行序列化(即只复制数组中有值的位置,未赋值的位置不进行序列化,节约空间)**/
3)源码分析
添加元素(add(E e)):思路为添加元素后进行数组索引判断,若大于原始数组容量则进行扩容,否则直接添加。
public
扩容(grow(int minCapacity):先获取原始数组长度,并且左移即扩大为原来的1.5倍,之后进行扩容后数组容量的校验,最后调用Arrays.copyOf将旧数组元素复制到新数组中。
ArrayList中的fail-fast机制: 我们知道 java.util.ArrayList 是线程不安全的,当发生线程不安全ArrayList将抛出ConcurrentModificationException,这就是所谓fail-fast策略。 这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示已经有其他线程修改了 ArrayList。
为什么扩容为原来的1.5倍?
通过google查找,发现1.5倍的扩容是最好的倍数。因为一次性扩容太大(例如2.5倍)可能会浪费更多的内存(1.5倍最多浪费33%,而2.5被最多会浪费60%,3.5倍则会浪费71%……)。但是一次性扩容太小,需要多次对数组重新分配内存,对性能消耗比较严重。所以1.5倍刚刚好,既能满足性能需求,也不会造成很大的内存消耗。
3、Vector原理详解
Vector 继承于AbstractList,实现了List, RandomAccess, Cloneable接口,因而其具有队列、随机访问和克隆的功能。与ArrayList不同的是Vector是线程安全的。
部分代码解释
public
4、ArrayList的优缺点:
ArrayList的优点:
a、ArrayList底层以数组实现,是一种随机访问模式,再加上它实现了RandomAccess接口,因此查找也就是get的时候非常快
b、ArrayList在顺序添加一个元素的时候非常方便,只是往数组里面添加了一个元素而已。
ArrayList缺点:
a、删除元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能
b、插入元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能
因此,ArrayList比较适合顺序添加、随机访问的场景。
5、 ArrayList和Vector的区别
a、Vector是线程安全的,ArrayList是线程非安全的
b、Vector可以指定增长因子,如果该增长因子指定了,那么扩容的时候会每次新的数组大小会在原数组的大小基础上加上增长因子;如果不指定增长因子,那么就给原数组大小*2。
其次, ArrayList是线程非安全的,这很明显,因为ArrayList中所有的方法都不是同步的,在并发下一定会出现线程安全问题。那么我们想要使用ArrayList并且让它线程安全怎么办?一个方法是用Collections.synchronizedList方法把你的ArrayList变成一个线程安全的List,比如 :
List
参考文章: