Java List 讲解

List 讲解

List是Java里边的一个接口,常用的实现类有ArrayList和LinkedList,在开发中用的最多的是ArrayList。

ArrayList

ArrayList的底层数据结构是数组。

Java本身就有数组了,为什么还要用ArrayList呢?

原生数组有一个特点:使用它的时候必须要为它创建大小,而ArrayList不用,ArrayList实现了动态扩容。

在日常开发中,往往我们是不知道要给数组分配多大数量的。

ArrayList的动态扩容

当我们new ArrayList()的时候,默认会有一个空Object数组,大小为0;

当我们第一次add添加数据的时候,会给这个数组初始化一个大小,默认是10;

使用ArrayList在每一次add的时候,它都会先去计算这个数组够不够空间;

如果空间是够的,直接尾部追加。不够,则需扩容;

源码里有个grow方法,每一次扩原来的1.5倍。空间扩容完成后,会调用arraycopy来对数组进行拷贝。

日常开发过程中为什么用ArrayList比较多?

是由底层的数据结构决定的,在日常开发中,遍历的需求比增删要多,即便是增删也是往往在List的尾部添加就OK了。像在尾部添加元素,ArrayList的时间复杂度也就O(1)。另外,ArrayList的增删底层调用的copyOf()被优化过,现代CPU对内存可以块操作,ArrayList的增删一点不会比LinkedList慢。

Vector

底层数据结构是数组,一般现在很少用了。

相对于ArrayList它是线程安全的,扩容时直接扩容两倍。

CopyOnWriteArrayList

CopyOnWriteArrayList是一个线程安全的List,底层是通过复制数组的方式来实现的。

add方法

首先会加lock锁,然后会复制出一个新的数组,往新的数组里边add真正的元素,最后把array的指向改变为新的数组。

get方法和size方法

只是获取array所指向的数组的元素或者大小。

CopyOnWriteArrayList的缺点

  1. 耗费内存,每次add都会复制一个数组出来。

  2. 只能保证数据的最终一致性,不能保证数据实时一致性。

    假设两个线程,线程A去读取CopyOnWriteArrayList的数据,还没有读完,线程B把这个List给清空了,线程A此时还是可以把剩余的数据给读出来。

posted @ 2021-07-27 13:57  CodeSweet  阅读(336)  评论(0编辑  收藏  举报