Java集合之List

概述

List是一个类似于数组的数据结构,可以存储任意类型的对象;

List中常用的主要有ArrayList、LinkedList两个实现类,本篇文章也是主要讲解这两种结构,如图:这两个List的继承结构也不相同,在后文的内容都会有所体现

ArrayList

底层结构

  • 底层使用数组来存储元素,相比原始数组,ArrayList更加灵活,可以根据数据量情况支持扩容
  • 实现了RandomAccess接口,标记着支持在常数时间下随机访问元素
  • 使用连续的内存空间
  • 新增和删除允许null

初始化

  1. 无参数直接初始化,默认大小是空数组,并不是大家常说的 10,10 是在第一次 add 的时候扩容的数组值
  2. 指定大小初始化
  3. 指定初始数据初始化

新增和扩容机制

新增就是往数组中添加元素,主要分成两步:

  1. 判断是否需要扩容,如果需要执行扩容操作;
  2. 直接赋值,若是指定下标位置新增元素,则需要将后面的元素都依次往后移动,因此这种情况下的时间复杂度是O(n)

‼️ 新增时,并没有对值进行严格的校验,所以 ArrayList 是允许 null 值

扩容:

  • 扩容后的大小是原来的1.5倍
  • ArrayList 中的数组的最大值是 Integer.MAX_VALUE,超过这个值,JVM 就不会给数组分配内存空间了

扩容的步骤:

  1. 新建一个符合预期的新数组
  2. 把旧数组中的数据拷贝到新数组中,通过System.arraycopy 方法进行拷贝,对于数组而言是浅拷贝,只是改变引用,速度比较快

删除

  • 新增的时候是没有对 null 进行校验的,所以删除的时候也是允许删除 null 值的;
  • 删除的方式: 根据数组索引删除、根据值删除或批量删除

删除的步骤:

  1. 找到值在数组中的索引位置,是通过 equals 来判断的,如果数组元素不是基本类型,需要我们关注 equals 的具体实现
  2. 把被删除元素后面的值往前移动,这一步也是导致删除操作的时间复杂度为O(n)

时间复杂度

操作

时间复杂度

解析

末尾插入/删除元素

O(1)

指定位置插入元素

O(n)

先移动元素,再插入

删除指定位置元素

O(n)

往前移动元素

根据index查询数据

O(1)

底层数组的特性,RandomAccess接口标记此特性

线程安全问题

先说结论:不安全

原因: ArrayList 自身的 elementData、size、modConut 在进行各种操作时,都没有加锁,而且这些变量的类型并非是可见(volatile)的,所以如果多个线程对这些变量进行操作时,可能会有值被覆盖的情况

LinkedList

底层结构

  • 底层使用双向链表实现。链表中的每个结点都有两部分组成,一部分是存储数据元素的值域,一部分是指向当前结点的前一个结点和后一个结点,所以LinkedList相对来说还需要额外的空间
  • 使用的是非连续的内存空间
  • 只能通过遍历访问数据,这也是LinkedList继承自AbstractSequentialList

时间复杂度

操作

时间复杂度

解析

头部/末尾 插入/删除元素

O(1)

指定位置插入/删除元素

O(1)

只需要通过变更结点指向完成插入/删除

但是对于需要查找确定位置的元素还是需要通过挨个遍历去查找到元素,然后再进行操作

查询数据

O(n)

在链表中要从头开始挨个遍历链表,直到找到目标元素

常用方法

方法名

说明

addFirst(E element)

添加新元素到列表的开头

getFirst()

返回列表的第一个元素

getLast()

返回列表的最后一个元素

removeFirst()

删除列表的第一个元素

removeLast()

删除列表的最后一个元素

应用场景

  • 不支持频繁随机访问元素的场景
  • 可以实现堆栈(先进后出)和双端队列(先进先出)

ArrayList和LinkedList对比

ArrayList

LinkedList

时间方面

  • 查询修改快
  • 新增删除慢
  • 查询修改慢
  • 新增删除快

空间方面

  • 使用连续空间
  • 需要提前分配一定大小的空间,容易造成空间浪费
  • 非连续空间
  • 不需要提前分配
  • 需要占用额外的内存空间记录前后元素的引用,在存储相同数量的元素时,通常会比ArrayList占用更大的空间
  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值