ArrayList、LinkedList、Queue分析

一、构造器创建ArrayList

  1. 构造器

    public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            }
        }
    ​
        /**
         * Constructs an empty list with an initial capacity of ten.
         */
        public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
  2. Object[] EMPTY_ELEMENTDATA = {}; // 长度传0时

  3. Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 无参构造

  4. 当我们已经知道要填充多少个元素到ArrayList中时建议使用指定长度传入,否则最好还是使用无参构造,防止执行多次的扩容等操作损耗性能。

  5. 为什么不能使用Arrays.asList构建的list来new ArrayList()

    1. 不是一个同包类

    2. 创建出来的list既不能删除也不能新增

    3. 因为ArrayList有一个构造函数是通过Collection类接收参数的,所有Arrays.asList可以创建ArrayList。

      public ArrayList(Collection<? extends E> c) {
              Object[] a = c.toArray();
              if ((size = a.length) != 0) {
                  if (c.getClass() == ArrayList.class) {
                      elementData = a;
                  } else {
                      elementData = Arrays.copyOf(a, size, Object[].class);
                  }
              } else {
                  // replace with empty array.
                  elementData = EMPTY_ELEMENTDATA;
              }
          }

二、ArrayList的插入操作

  1. 插入操作就是对数组的操作,就是需要扩容。

  2. 数组是定长的,如果超过原来的定长长度,扩容则需要申请新的数组长度并把原数组元素拷贝到新数组中。

  3. 每次扩容都会增加原容量的三分之二。

  4. 指定位置插入

    1. 判断size是否可以插入

    2. jdk17版本:判断是否已经达到了最大长度,达到了则扩容

    3. 判断插入后是否需要扩容

    4. 数据元素迁移,把待插入位置后的元素,顺序往后迁移。

    5. 给数组的指定位置赋值,也就是把待插入元素插入进来。

    6. Jdk17源码

    public void add(int index, E element) {
            rangeCheckForAdd(index);
            modCount++;
            final int s;
            Object[] elementData;
            if ((s = size) == (elementData = this.elementData).length)
                elementData = grow();
            System.arraycopy(elementData, index,
                             elementData, index + 1,
                             s - index);
            elementData[index] = element;
            size = s + 1;
        }

三、LinkedList、ArrayList插入分析

  1. 两种集合哪一个插入数据的速度更快,需要分情况分析

    1. 如果是头插入,LinkedList速度会更快,如果是中间插入是ArrayList快一点,如果是尾插入,是ArrayList的速度要更快。

  2. 同样的删除操作因为需要找到具体的位置,如果是删除中间元素的情况下,LinkedList也是很慢的。

  3. 遍历时如果是LinkedList最好是使用迭代器和foreach,如果使用fori的循环LinkedList的时间复杂度会达到O(n2)

四、双端队列、延迟队列、阻塞队列

  1. 前置的Stack,被抛弃的栈实现类

    1. 因为是后进先出且它的底层实现是Vector数组,Vector锁的颗粒度太大,都是直接到方法上的,所以性能并不好。并且使用的是数组结构性能也不好不好。

  2. 双端队列ArrayDeque

    1. 结构:数组实现,所以会有扩容迁移数据的操作

    2. 双端队列就是一个环形,所以扩容后继续插入元素也满足后进先出。

    3. 实现默认容量和HashMap的容量类似,都是以传输量最小的2倍数的一个容量。

    4. 当头和尾相接,数组则需要两倍的扩容。

  3. 双端队列LinkedList

    1. 天生支持双端队列,且从头尾取数据时间复杂度也是O(1)。

    2. 链表和数组的最大区别就是没有扩容和复制的操作,所以LinkedList就是天生的双端队列,但较之ArrayDeque的性能相比,也只是在向头插入的时候快了一些,因为如果是尾插入,ArrayDeque的损耗仅在于扩容操作,而LinkedList则需要不断地创建对象。

  4. 延时队列DelayQueue

    1. 设定存放时间,依次轮询获取。

    2. 队列中的元素不会因为存放的先手顺序而导致输出顺序,它们是依赖于休眠时长决定的。

    3. DelayQueue时Leader-Followr模式的变种,消费者线程处于等待时,总是等待最先休眠完成的元素。

五、其他队列

  1. 类型

    实现

    描述

    Queue

    LinkedBlockingQueue

    由链表结构组成的有界阻塞队列

    Queue

    ArrayBlockingQueue

    由数组结构组成的有界阻塞队列

    Queue

    PriorityBlockingQueue

    支持优先级排序的无界阻塞队列

    Queue

    SynchronousQueue

    不存储元素的阻塞队列

    Queue

    LinkedTransferQueue

    由链表结构组成的无界阻塞队列

    Deque

    LinkedBlockingDeque

    由链表结构组成的双向阻塞队列

    Deque

    ConcurrentLinkedDeque

    由链表结构组成的线程安全的双向阻塞队列

    机制和队列没有差异,剩下的就是添加了阻塞功能和锁的机制。

六、总结

  1. ArrayList的数据结构是什么?

    1. 基于数组实现,当数组满了的时候就进行扩容操作。

  2. LinkedList和ArrayList的区别在哪

    1. LinkedList是链表实现,ArrayList是数组实现

    2. LinkedList的头尾插入速度比较快,中间插入、删除操作比较慢,ArrayList的头插入速度较慢,尾插入速度快,原因在于:LinkedList的头尾插入操作只需要实例化对象并进行绑定操作即可,但中间插入的情况下,会出现O(n2)级别的操作,十分耗时,原因在于它不存在下标,向中间插入的时候需要进行遍历操作再绑定赋值。但如果是ArrayList的中间插入操作,它是数组结构实现,它所带来的损耗最多也就是copy数组和扩容操作的情况会影响它的性能。

  3. 队列有哪几种

    1. 双端队列,延时队列,阻塞队列

      1. 双端队列就是头和尾都可以进行弹出,比如LinkedList就是天生的双端队列,它都可以进行头尾的取值。

      2. 双端队列还有数组结构实现的ArrayDeque

    2. 延时队列的使用场景

      1. 可以在执行某些任务的时候使用,比如延时删除,延时发送消息等。

    3. 阻塞队列

  • 28
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值