Java常用数据结构(二)——列表(1):ArrayList、LinkedList、Vector的实现原理和区别

基本概念

在开发过程中,数组一旦初始化后,长度就确定了,存储数据对象不能达到动态扩展,其次数组存储元素不便于对数组进行添加、修改、删除操作,而且数组可以存储重复元素。相比之下,Java集合就像是一个容器,可以存储任何类型的数据,也可以结合泛型来存储具体的类型对象。在程序运行过程中,Java集合可以动态的进行扩展。因此,Java集合类更加适合于现代开发需求。

  • 集合接口结构可以看出Java集合主要由2大体系构成,分别Collection体系和Map体系,其中CollectionMap分别是2大体系中的顶层接口。

  • Collection主要有三个子接口,分别为List(列表)Set(集)Queue(队列)。其中,List、Queue中的元素有序可重复,而Set中的元素无序不可重复。

  • List中有ArrayListLinkedList以及Vector三个实现类。

我将从下面几个方面简单概括一下三个实现类的实现原理和区别:
存储结构
ArrayList和Vector的底层都是通过数组实现的,因此和数组类似,可以通过下标访问,默认初始容量为10,可以动态扩容;
LinkedList的底层则是使用含头结点的双向链表实现。

线程安全性
三者中,只有Vector是线程安全的类,因为它的大部分方法都包含关键字synchronized,但如果是开发中没有线程同步的需求,推荐优先使用ArrayList。因此其内部没有synchronized关键字,执行效率会比Vector快很多;如果需要在并发环境下使用ArrayList和LinkedList类,可以通过调用Collections类中的静态方法synchronizedList()来保证线程安全;

扩容机制
从内部实现机制来讲,ArrayList和Vector都是使用Object的数组形式来存储的,当向这两种类型中增加元素的时候,若容量不够,需要进行扩容。
在这里需要说一下可变长度数组的原理:当元素个数超过数组的长度时,会产生一个新的数组,将原数组的数据复制到新数组,再将新的元素添加到新数组中。
ArrayList在JDK1.8中的扩容过程:

  /**
     ArrayList扩容后的容量是之前的1.5倍,然后把之前的数据拷贝到新建的数组中去。
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//表明最大的数组容量是Integer.MAX_VALUE-8,对于空出的8位,官方解释是:1.存储Headerwords; 2.避免一些机器内存的溢出,减少出错率; 3.最大还是能支持到Integer.MAX_VALUE.
    
    private void grow(int minCapacity) {
        // overflow-conscious code
        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);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

和ArrayList类中不同的是,Vector可以设置容量增量,而ArrayList则不行。在Vector中,有容量增量参数capacityIncrement:当大小大于其容量时,容量自动增加的量。如果在创建Vector时,指定了capacityIncrement的大小,则Vector中动态数组容量需要增加时,如果容量的增量大于0,则增加的是大小是capacityIncrement,如果增量小于0,则增大为之前的2倍。

Vector在JDK1.8中的扩容过程:

/**
      Vector扩容后的容量是之前的2倍,然后把之前的数据拷贝到新建的数组中去。
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

操作效率
ArrayList和Vector效率差别不大,区别在于使用场景,因为Vector类是线程安全的,所以适用于多线程场景。重点比较ArrayList和LinkedList的操作效率:

ArrayListLinkedList
底层是线性表(数组)底层是链表操作
get()直接读取某个元素,复杂度O(1)get()获取某个元素,需要依次遍历,复杂度O(n)
add(x),直接在尾部添加,复杂度O(1)add(x), 直接在尾部添加,复杂度O(1)
add(index,E)添加元素,后面的元素需要向后移动,复杂度O(n)add(index,E)添加元素,需要先查找到元素位置,然后直接指针指向操作,复杂度O(n)
remove()删除元素,后面的元素需要逐个移动,复杂度O(n)remove()删除元素,直接指针指向操作,复杂度O(1)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值