一. Array
Array(数组)是基于索引(index)的数据结构,且它占用的内存空间是连续的,所以搜索和读取数据时使用索引在数组中是很快的。
Array获取数据的时候非常快,直接通过索引找到数据,时间复杂度是O(1);但是要删除数据却是开销很大,因为删除数据后需要把后面剩下的所有数据前移。
注意:数组初始化必须指定初始化的长度, 否则报错。
eg:
int[] x = new int[];//报错,没有初始化长度
int[] x = new int[5];//正确,初始数组长度为5(index范围为0 - 4)
二. List
List可以包含重复的元素,使用按索引访问的方式,继承于Collection。
List是一个接口,不可以直接实例化,其中介绍四个重要的实现类:
ArrayList、LinkedList、CopyOnWriteArrayList和Vector。
他们的继承关系如下:
继承截图:
继承结构图:
三.ArrayList
ArrayList 可以看作是能够自动增长容量的数组,ArrayList底层的实现是Array,故ArrayList的容量可以扩展,但是需要连续的内存空间。
例子:
ArrayList 的实例ArrayX数组,当前占三个内存资源,数组大小为3,当添加第四个数据时,ArrayX会自动扩容,扩容的过程为:
(1)判断当前数组之后有无连续的内存空间,如有则直接在数组之后扩容然后添加数据;
(2)如果当前数组之后没有可用空间,则往下找,找到能够装下添加数据之后的数组的连续内存空间,然后申请空间,将之前的数组复制到这一块连续的内存空间,然后在这个复制过来的新数组后添加该数据;
(3)将原来的老数组占用的内存空间回收。
如下图:
说明:ArrayList在初始化的时候指定长度要比不指定长度的性能好很多, 这样不用重复的申请空间, 复制数组, 销毁老的数组。
如下代码,在不断增加数据的过程,2比1执行速度更快。
public static int length = 1024;
//1.未指定长度
List<Integer> list1 = new ArrayList<>();
//2.指定长度
List<Integer> list2 = new ArrayList<>(length);
四.LinkList
LinkList是一个双链表,在get与set方面比ArrayList差,即查找数据时在平均性能上比ArrayList更差,但在添加和删除元素时具有比ArrayList更好的性能。LinkList的存储不需要连续的存储空间。
例子:
LinkList 的实例LinkX数组,当前占三个内存资源,链表大小为3,当添加第四个数据时,过程为:
(1)链表不需要连续的空间, 直接找到空闲的内存空间存下数据。
如下图:
五.CopyOnWriteArrayList
CopyOnWriteArrayList和 ArrayList一样,也是通过数组实现的,但确是线程安全容器(相对于 ArrayList),增加删除等写操作通过加锁的形式保证数据一致性,通过复制新集合的方式解决遍历迭代的问题。
CopyOnWriteArrayList的增删改都需要获得锁,并且锁只有一把,而读操作不需要获得锁,支持并发。在增删改的过程中都会创建一个新的数组,操作完成之后再赋给原来的引用,这是为了保证get的时候都能获取到元素,如果在增删改过程直接修改原来的数组,那么可能会造成执行读操作获取不到数据。因此在增删改的过程中都会先创建一个数组。待操作完成之后再将新数组的引用赋值给array。
几个要点
- CopyOnWriteArrayList内部持有一个ReentrantLock lock = new ReentrantLock();
- 底层是用volatile transient声明的数组 array
- 读写分离,写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array
六.Vector
Vector(向量类)与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。vector是线程(Thread)同步(Synchronized)的,所以它也是线程安全的,而Arraylist是线程异步(ASynchronized)的,是不安全的。如果不考虑到线程的安全因素,一般用Arraylist效率比较高。
7.总结
1.ArrayList和LinkList的区别:
(1)ArrayList是基于数组的,存储需要连续的存储空间,LinkList是基于链表的,存储不需要连续的存储空间;
(2)如果需要大量的查询数据,使用ArrayList,如果需要大量的增删数据,使用LinkList。
2.ArrayList、CopyOnWriteArrayList、Vector的区别:
(1)ArrayList非线程安全的,如果需要考虑到线程安全问题,那么可以使用Vector和CopyOnWriteArrayList;
(2)Vector和CopyOnWriteArrayList的区别是 : 是增删改查方法都加了synchronized,保证同步,但是每个方法执行的时候都要去获得锁,性能就会大大下降,而CopyOnWriteArrayList 只是在增删改上加锁,但是读不加锁,在读方面的性能就好于Vector,CopyOnWriteArrayList支持读多写少的并发情况。