2. List

Java的List是非常常用的数据类型,List是有序的集合,可以包含重复的元素,可以有多个元素引用相同的对象,提供了按索引访问的方式,继承自Collection。
Java List一共三个实现类:分别是ArrayList、Vector和LinkedList。

1. ArrayList(数组)
ArrayList是最常用的List实现类,内部是通过Array(数组)实现的,Array(数组)是基于索引(index)的数据结构,是数组动态扩容实现,它使用索引在数组中搜索和读取数据很快,占用连续的内存空间。
Array获取数据的时间复杂度是O(1),但要删除数据的开销却是很大,因为这需要重排数组中的所有数据,删除数据后需要把后面所有的数据前移,时间复杂度为O(n)。
因此它适合随机查找和遍历,不适合插入和删除。
ArrayList的toArray()方法返回一个数组,asList()返回一个列表

ArrayList 的扩容机制
ArrayList扩容的本质就是计算出新的扩容数组的size后实例化,并将原有数组内容复制到新数组中去。默认情况下,初始容量为10,新的容量会是原容量的1.5倍。以JDK1.8为例说明:

点击查看代码
public boolean add(E e) {
    //判断是否可以容纳e,若能,则直接添加在末尾;若不能,则进行扩容,然后再把e添加在末尾
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //将e添加到数组末尾
    elementData[size++] = e;
    return true;
    }

// 每次在add()一个元素时,arraylist都需要对这个list的容量进行一个判断。通过ensureCapacityInternal()方法确保当前ArrayList维护的数组具有存储新元素的能力,经过处理之后将元素存储在数组elementData的尾部

private void ensureCapacityInternal(int minCapacity) {
      ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //如果传入的是个空数组则最小容量取默认容量与minCapacity之间的最大值
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    
  private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // 若ArrayList已有的存储能力满足最低存储要求,则返回add直接添加元素;如果最低要求的存储能力>ArrayList已有的存储能力,这就表示ArrayList的存储能力不足,因此需要调用 grow();方法进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }


private void grow(int minCapacity) {
        // 获取elementData数组的内存空间长度
        int oldCapacity = elementData.length;
        // 扩容至原来的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //校验容量是否够
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //若预设值大于默认的最大值,检查是否溢出
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 调用Arrays.copyOf方法将elementData数组指向新的内存空间
         //并将elementData的数据复制到新的内存空间
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

2. Vector(数组实现 线程同步)
Vector与ArrayList一样,也是通过数组实现的, 不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢,Vector默认情况下的扩容为原来的2倍。

3. LinkedList(链表)
LinkedList内部是用链表结构存储数据的,很适合数据的动态插入和删除,不需要连续的内存空间。
LinkedList随机访问速度慢,需要从头节点开始遍历,时间复杂度为O(n),在中间插入和删除元素较快,只需要修改节点的引用,时间复杂度为O(1),

posted on 2024-12-22 21:36  南柯易梦  阅读(1)  评论(0编辑  收藏  举报