ArrayList与Vector

ArrayList

ArrayList 是 Java 集合框架中最常用的类之一,它实现了 List 接口,基于动态数组的数据结构。ArrayList 提供了快速的随机访问能力,并且支持动态扩容,适合存储和操作大量数据

特点

  • 基于动态数组
    • ArrayList 内部使用数组来存储元素。
    • 数组的大小可以动态调整,当元素数量超过当前数组容量时,会自动扩容
  • 有序且允许重复
    • 元素按照插入顺序存储。
    • 允许存储重复的元素
  • 允许 null 元素
    • ArrayList 可以存储 null 值,且可以存储多个 null
  • 非线程安全,ArrayList 不是线程安全的。

常用方法

ArrayList 实现了 List 接口,因此支持 List 的所有方法。

ArrayList底层实现

  1. transient Object[] elementData

    • 这是一个 Object 类型的数组,用于存储 ArrayList 中的元素
    • 数组的长度(elementData.length)表示当前 ArrayList 的容量(Capacity),即最多可以存储多少个元素。
    • 数组的实际使用长度(即 ArrayList 中存储的元素数量)由 size 字段表示
    • 在 ArrayList 中,存储数据的数组 elementData 被声明为 transient,但这并不意味着数据完全不参与序列化。相反,ArrayList 通过自定义序列化逻辑优化了存储效率
    • 反序列化时,ArrayList 会根据写入的实际元素数量重新分配一个容量精确匹配的数组,避免冗余空间占用
  2. int size

    • 表示 ArrayList 中实际存储的元素数量。
    • size 的值总是小于或等于 elementData.length

构造方法

  1. 无参构造方法

    • 默认构造方法会将 elementData 初始化为一个空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA。

    • 在第一次添加元素时,elementData 会扩容到默认容量(10)

      private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
      
      public ArrayList() {
          this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
      }
      
  2. 指定初始容量的构造方法

    • 如果指定了初始容量(initialCapacity),elementData 会被初始化为一个指定长度的数组。

    • 如果初始容量为 0,elementData 会被初始化为一个空数组 EMPTY_ELEMENTDATA

      private static final Object[] EMPTY_ELEMENTDATA = {}
      
      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);
          }
      }
      
  3. 基于集合的构造方法

    • 该构造方法会将指定集合 c 中的元素复制到 elementData 数组中。

    • 如果集合 c 为空,elementData 会被初始化为一个空数组 EMPTY_ELEMENTDATA

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

ArrayList的扩容机制

  • ArrayList 的容量是动态调整的。当元素数量超过当前数组容量时,ArrayList 会自动扩容
  • 新容量通常是旧容量的 1.5 倍
  • 如果所需容量超过 MAX_ARRAY_SIZE,则返回 Integer.MAX_VALUE
  • 扩容需要创建新数组并复制数据,可以通过指定初始容量来减少扩容次数,避免不必要的扩容操作
  1. 扩容的触发条件

    • 扩容通常在添加元素时触发,例如在 add() 方法中
    • ensureCapacityInternal(size + 1) 会检查当前容量是否足够,如果不足则调用 grow() 方法扩容。
    • 当添加元素时,如果当前容量不足(即 size + 1 > elementData.length),ArrayList 会自动扩容
    public boolean add(E e) {
        ensureCapacityInternal(size + 1); // 确保容量足够
        elementData[size++] = e;
        return true;
    }
    
  2. 扩容逻辑主要集中在 grow() 方法中

    • grow(int minCapacity) 方法
    private void grow(int minCapacity) { //minCapacity:所需的最小容量(通常是 size + 1)
        int oldCapacity = elementData.length; // 当前容量
        int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量为旧容量的 1.5 倍
        if (newCapacity - minCapacity < 0) // 如果新容量仍然不足
            newCapacity = minCapacity; // 直接使用所需的最小容量
        if (newCapacity - MAX_ARRAY_SIZE > 0) // 如果新容量超过最大限制
            newCapacity = hugeCapacity(minCapacity); // 处理超大容量
        elementData = Arrays.copyOf(elementData, newCapacity); // 创建新数组并复制数据
    }
    
    • hugeCapacity(int minCapacity) 方法
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // 如果所需容量溢出(超过 Integer.MAX_VALUE)
            throw new OutOfMemoryError(); // 抛出内存溢出异常
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }
    
    //如果所需容量超过了 MAX_ARRAY_SIZE,则返回 Integer.MAX_VALUE。
    //如果所需容量溢出(即 minCapacity < 0),则抛出 OutOfMemoryError
    

Vector

  • Vector 与 ArrayList 类似,但它是 线程安全 的
  • Vector 实现了 List 接口,因此支持 List 的所有方法。
  • 默认10,Vector 默认扩容为 2 倍
posted @ 2025-03-03 21:57  QAQ001  阅读(10)  评论(0)    收藏  举报