java 集合类之ArrayList、LinkedList 和Vector

本文详细对比了ArrayList、Vector和LinkedList的特点与应用场景,探讨了它们的线程安全性、动态扩展策略及内部实现机制,帮助读者在不同场景下选择合适的集合类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天和朋友聊天,谈到java中的集合类问题,对于其中的用法和特点有些遗忘的地方,再次梳理和记录下。首先是常用的ArrayList 和Vector。(java 8),狭义(不包含Map)集合类UML 图:

联系和区别:

ArrayList  和Vector 都继承了AbstractList,而和LinkedList 同时实现了List 接口,因此具有List的一些特点,比如底层都是用数组来存储的。也因此两者有数组有关的优缺点比如根据下标进行访问,查询速度快,时间复杂度O(1),缺点是添加和删除涉及到元素的复制、移动问题,效率相对低的缺点。提供了迭代器遍历的功能

1、ArrayList是线程不安全的类;而Vector是线程安全的集合类,源码中Vector类对集合的元素操作时都加了synchronized,保证线程安全。也因此在不考虑线程安全的前提下,相比Vector,效率上ArrayList 相对高效写(大家都这么说)

2、动态扩展方面:Vector默认扩容是先判断整张因子是否大于0,(默认为0),若大于0,则将数组大小扩大为size+capacityIncrement,否则增长一倍的容量,Arraylist是增长50%的容量。

3、LinkedList 是java提供的双向链表,进行节点插入删除要高效很多,但是随即访问要比动态数组慢,不需要像上面两种调整容量,线程也是不安全的。

因此,在选用哪个集合类存储时要根据使用场景进行针对性的选择。

源码分析:

首先是ArrayList :

构造方法:

/**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    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;
    }

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

可以看到,调用无参构造函数,有初始化容量的话,创建一个初始化容量大小的数组,没有到话创建一个空数组,在调用add 方法时会进行真正初始化.使用默认的初始化容量10.

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }



private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }


 private void ensureExplicitCapacity(int minCapacity) {
        // 将“修改统计数”+1,该变量主要是用来实现fail-fast机制的
        modCount++;
        // 防止溢出代码:确保指定的最小容量 > 数组缓冲区当前的长度
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

其中ensureCapacityInternal()方法当第一次数组为空时,将minCapacity 设置为10,后续比较时,当添加的元素小于10个的时候不扩容,当添加第11 个时,此时ensureCapacityInternal(int minCapacity =11),比较后11- 10>0,进行扩容。

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 运算符 >> 是带符号右移
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        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);
    }

进行右移后时间上是*0.5。

Vector:

先看下构造方法:

无参构造
    /**
     * Constructs an empty vector so that its internal data array
     * has size {@code 10} and its standard capacity increment is
     * zero.
     */
    public Vector() {
        this(10);
    }
     public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

和ArrayList 类似,默认Vector 也会创建一个初始容量为10的数组,其容量增量为0;

add()方法:

可以看到,add方法上已经使用了synchronized .

public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }


private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

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);
    }

可以看到,Vector 在扩容的时候,先判断增量因子是否大于0 ,大于0的话在原来的基础上+capacityIncrement,否则的话就是加上oldCapacity.

关于其他方法,就不一一介绍了,最好是通过Demo+debug的方式一步一步跟踪,方得始终,就酱。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值