java基础-容器-List

说下你对List的理解?
List在Java里边是一个接口,常见的实现类有ArrayList和LinkedList,在开发中用得最多的是ArrayList;
ArrayList的底层数据结构是数组,LinkedList底层数据结构是链表。

List和Set的区别?
List:有序,按对象进入的顺序保护对象,可重复,允许多个null元素对象,可以使用iterator取出所有元素,在逐一遍历,还可以使用get获取制定下标元素。
Set:无序,不可重复,最多允许有一个NULL元素对象,取元素时只能Iterator接口取得所有元素,在逐一遍历各个元素。

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

原生的数组会有一个特点:你在使用的时候必须要为它创建大小,而ArrayList不用。
如果数组的大小指定多了,内存浪费;如果数组大小指定少了,装不下。
假设我们给定数组的大小是10,要往这个数组里边填充元素,我们只能添加10个元素。
而ArrayList不一样,ArrayList我们在使用的时候可以往里边添加20个,30个,甚至更多的元素;
因为ArrayList是实现了动态扩容的
当我们new ArrayList()的时候,默认会有一个空的Object数组,大小为0。
当我们第一次add添加数据的时候,会给这个数组初始化一个大小,这个大小默认值为10

使用ArrayList在每一次add的时候,它都会先去计算这个数组够不够空间;
如果空间是够的,那直接追加上去就好了。如果不够,那就得扩容;
在源码里边,有个grow方法,每一次扩原来的1.5倍。比如说,初始化的值是10嘛。
现在我第11个元素要进来了,发现这个数组的空间不够了,所以会扩到15;
空间扩完容之后,会调用arraycopy来对数组进行拷贝;
是由底层的数据结构来决定的,在日常开发中,遍历的需求比增删要多,即便是增删也是往往在List的尾部添加就OK了。
在日常开发中用得最多的是ArrayList呢?
是由底层的数据结构来决定的,在日常开发中,遍历的需求比增删要多,即便是增删也是往往在List的尾部添加就OK了。
像在尾部添加元素,ArrayList的时间复杂度也就O(1);
另外的是,ArrayList的增删底层调用的copyOf()被优化过;
现代CPU对内存可以块操作,ArrayList的增删一点儿也不会比LinkedList慢;

线程安全的List还有什么?

在java.util.concurrent包下还有一个类,叫做CopyOnWriteArrayList,
是一个线程安全的List,底层是通过复制数组的方式来实现的。

在add()方法其实他会加lock锁,然后会复制出一个新的数组,往新的数组里边add真正的元素,最后把array的指向改变为新的数组。
get()方法又或是size()方法只是获取array所指向的数组的元素或者大小。读不加锁,写加锁。
CopyOnWriteArrayList有什么缺点吗?
CopyOnWriteArrayList是很耗费内存的,每次set()/add()都会复制一个数组出来;
另外就是CopyOnWriteArrayList只能保证数据的最终一致性,不能保证数据的实时一致性。
假设两个线程,线程A去读取CopyOnWriteArrayList的数据,还没读完。
现在线程B把这个List给清空了,线程A此时还是可以把剩余的数据给读出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值