Java集合:List

以你之姓@ 2022-12-02 10:59 422阅读 0赞

一、集合概述

在Java中,我们能想到的List接口下的类有那么两个半吧:①ArrayList,②LinkedList,③Vector。
ArrayList:

  • 底层是数组
  • 初始容量为10,每次扩容为1.5倍
  • 组的增删改底层由System和Arrays的数组赋值拷贝方法支持

LinkedList:

  • 底层是双向链表

插入/删除操作适合LinkedList,查询操作适合ArrayList,Vector就是线程安全的ArrayList。

二、ArrayList

这里就直接上源码吧,先来看看成员变量和构造方法:

  1. // 数组默认容量
  2. private static final int DEFAULT_CAPACITY = 10;
  3. // 空数组
  4. private static final Object[] EMPTY_ELEMENTDATA = { };
  5. // 默认大小的空数组
  6. private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = { };
  7. // 实际存放数据的数组
  8. transient Object[] elementData;
  9. // 记录数组的大小
  10. private int size;
  11. // 有指定容量构造
  12. public ArrayList(int initialCapacity) {
  13. if (initialCapacity > 0) {
  14. this.elementData = new Object[initialCapacity];
  15. } else if (initialCapacity == 0) {
  16. this.elementData = EMPTY_ELEMENTDATA;
  17. } else {
  18. throw new IllegalArgumentException("Illegal Capacity: "+
  19. initialCapacity);
  20. }
  21. }
  22. // 空参构造
  23. public ArrayList() {
  24. this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  25. }

从上面我们可以看出有三种情况:

  1. 使用空参构造器,我们会收获一个默认容量大小的空数组,也就是DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  2. 使用参数为容量大小的构造器,如果initialCapacity为0,则赋值EMPTY_ELEMENTDATA;如果initialCapacity不为0,则构造一个initialCapacity大小的数组

那EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDATA有啥不一样呢?后面会有解析:

add方法:

  1. public boolean add(E e) {
  2. // 确认数组是否需要扩容
  3. ensureCapacityInternal(size + 1);
  4. // 添加元素即可
  5. elementData[size++] = e;
  6. return true;
  7. }

扩容方法:

  1. private void ensureCapacityInternal(int minCapacity) {
  2. // 如果是使用空参构造器构建的集合对象
  3. // 前面的疑问就在这里解决
  4. if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
  5. // 重新计算minCapacity
  6. minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
  7. }
  8. ensureExplicitCapacity(minCapacity);
  9. }
  10. //
  11. private void ensureExplicitCapacity(int minCapacity) {
  12. // 操作次数+1
  13. modCount++;
  14. // 如果minCapacity >elementData.length,执行扩容操作
  15. if (minCapacity - elementData.length > 0)
  16. grow(minCapacity);
  17. }
  18. private void grow(int minCapacity) {
  19. // 获取旧数组的长度
  20. int oldCapacity = elementData.length;
  21. // 计算新数组的长度,长度 = 1.5*旧数组的长度,也就是1.5倍扩容
  22. int newCapacity = oldCapacity + (oldCapacity >> 1);
  23. //
  24. if (newCapacity - minCapacity < 0)
  25. newCapacity = minCapacity;
  26. // MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
  27. // 计算出来的新数组长度已经 大于 最大数组大小
  28. if (newCapacity - MAX_ARRAY_SIZE > 0)
  29. // 重新计算新数组长度
  30. newCapacity = hugeCapacity(minCapacity);
  31. // 复制数组到新数组
  32. elementData = Arrays.copyOf(elementData, newCapacity);
  33. }
  34. // 重新计算新数组长度
  35. private static int hugeCapacity(int minCapacity) {
  36. if (minCapacity < 0)
  37. throw new OutOfMemoryError();
  38. return (minCapacity > MAX_ARRAY_SIZE) ?
  39. Integer.MAX_VALUE :
  40. MAX_ARRAY_SIZE;
  41. }

get方法: 正常的数组访问方式

  1. public E get(int index) {
  2. rangeCheck(index);
  3. return elementData(index);
  4. }
  5. E elementData(int index) {
  6. return (E) elementData[index];
  7. }

remove方法:

  1. public E remove(int index) {
  2. rangeCheck(index);
  3. modCount++;
  4. // 获取元素
  5. E oldValue = elementData(index);
  6. // 计算位移的位数
  7. int numMoved = size - index - 1;
  8. if (numMoved > 0)
  9. // 复制数组
  10. System.arraycopy(elementData, index+1, elementData, index,
  11. numMoved);
  12. elementData[--size] = null;
  13. return oldValue;
  14. }

例如:n数组,下标0~n-1,我们要删除第k位的数值,我们就需要将0 ~ k-1位以及k+1 ~ n-1的数组复制到新数组。

三、LinkedList

LinkedList底层是双向链表,那我们脑普一下就该知道,重点在Node节点上,其余的按照链表的方式来。
Node节点

  1. private static class Node<E> {
  2. // 保存的数据
  3. E item;
  4. // 保存的后继节点
  5. Node<E> next;
  6. // 保存的前驱节点
  7. Node<E> prev;
  8. Node(Node<E> prev, E element, Node<E> next) {
  9. this.item = element;
  10. this.next = next;
  11. this.prev = prev;
  12. }
  13. }

成员变量:

  1. // 记录队列的大小
  2. transient int size = 0;
  3. // 指向队列的头结点
  4. transient Node<E> first;
  5. // 指向队列的尾节点
  6. transient Node<E> last;

双向链表的基本操作,不会推荐去手写下链表即可。

四、Vector

与ArrayList的不同在于每个操作方法上都添加了synchronized关键字,也就是加了锁,保证线程安全,不过也大大降低了性能。

发表评论

表情:
评论列表 (有 0 条评论,422人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java List集合

    目录 List集合 特点: 特有方法: 遍历: -------------------- List集合 特点: 有序:存和取得顺序一致 有索引:可以

    相关 Java List集合

    List是有序的collection,可以对列表中每个元素的插入位置进行精确的控制 List集合的特点: 有序,存进去是这样,取出来还是按照存进去的顺序取出

    相关 Java集合List

    从上篇博客,我们知道了Java集合框架分为Collection和Map,此篇博客开始,将对集合框架中的List,Set,Queue和Map分别总结,进一步学习Java集合。本篇

    相关 Java集合--List

    Java集合–List Java集合 作为一个Developer,Java集合类是我们在工作中运用最多的、最频繁的类。相比于数组(Array)来说,集合类的长度可变

    相关 JavaList集合

    List集合 作为Collection集合的一个子类,其特点 1)有序,可重复 2)有索引可以使用普通的for循环遍历。 List 接口在 iterator、add、r