ArrayList与Vector源码解析与区别

ArrayList


1、ArrayList介绍

        ArrayList是一种线性数据结构,它的底层是用数组实现的,相当于动态数组。与Java中的数组相比,它的容量能动态增长,默认容量大小为10

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
     
     transient Object[] elementData;    
    /**
     * 构造初始容量为10的空列表。本质上为一个数组结构的集合
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

       当创建一个数组的时候,就必须确定它的大小,系统会在内存中开辟一块连续的空间,用来保存数组,因此数组容量固定且无法动态改变。ArrayList在保留数组可以快速查找的优势的基础上,弥补了数组在创建后,要往数组添加元素的弊端。实现的基本方法如下: 

1. 快速查找:在物理内存上采用顺序存储结构,因此可根据索引快速的查找元素。

2. 容量动态增长: 当数组容量不够用时,创建一个比原数组容量大的新数组(原来的一半),将数组中的元素复制到新数组,再将新数组赋给原数组成员变量,最后将新元素放进数组中。源码如下:

    //将数据增加到集合中
    public boolean add(E e) {
        //确定ArrayList的容量大小
        ensureCapacityInternal(size + 1);  // Increments modCount!!
       //添加e到ArrayList中
        elementData[size++] = e;
        return true;
    }

    //返回容器元素数量,加入新元素后的容量跟初始化容量对比
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
          if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
              return Math.max(DEFAULT_CAPACITY, minCapacity);
          }
          return minCapacity;
     }

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

     private void ensureExplicitCapacity(int minCapacity) {
          modCount++;

            // 判断容器是否溢出,即超出初始化大小,超出就自动增加容量
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
    }
    
    /**
     * 增加容量,以确保它至少可以容纳由minimum capacity参数指定的元素数。
     *
     * @param minCapacity the desired minimum capacity
     */
    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);
        // 创建新的数组(大小为newCapacity),将原数组中的元素复制到新数组,并将新数组赋值给elementData 成员变量,
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

总结,向集合中添加元素实现动态规则如下步骤:

(1)判断集合元素的个数与集合初始化大小对比

(2)增加元素后的个数大于默认容器大小,则创建新数组(数组大小为原来的一半),并将原数组元素复制到新数组中

(3)将新创建的数组赋予集合中数组成员变量elementData 

(4)数组成员变量接受新元素

2、ArrayList遍历方式

(1) 第一种,通过迭代器遍历。即通过Iterator去遍历。

Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}

(2) 第二种,通过索引值去遍历。

Integer value = null;
int size = list.size();
for (int i=0; i<size; i++) {
    value = (Integer)list.get(i);        
}

(3) 第三种,for循环遍历。如下:

Integer value = null;
for (Integer integ:list) {
    value = integ;
}

比较这3种方式的效率:遍历ArrayList时,使用随机访问(即,通过索引序号访问)效率最高,而使用迭代器的效率最低!

3、ArrayList线程不安全

4、ArrayList性能分析

(1)查询速度快

          ArrayList底层本身以数组的结构存储数据,初始化时默认创建容量为10的数组,并具有一个的排列顺序。通过索引能快速定位到数组的具体位置,并获取到该位置上的元素;

(2)增加或删除元素时,操作的位置不同,对数组存储数据的性能影响也不用

         当在数组的尾部新增(或删除)元素,则在该位置上直接添加新元素(或删除、清空该元素),其他的位置上的数组元素保持不变,操作的速度非常的快;

        但是,当新增(或删除)的元素位置不在首尾两端,而是在其中的某一个位置,则这过程将涉及到数组元素的内存问题,新增或删除指定位置的元素时,后面的元素将向前移动位置,填充该位置,达到数组的连续性,在元素移动位置过程中,将大大的降低了数组存储数据的效率;


Vector

1、Vector本质上为动态数组结构,默认容量为10,其的构造函数如下:

    /**
     * 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;
    }

2、添加元素时,线程安全

    /**
     * Appends the specified element to the end of this Vector.
     *
     * @param e element to be appended to this Vector
     * @return {@code true} (as specified by {@link Collection#add})
     * @since 1.2
     */
    public synchronized boolean add(E e) {
        modCount++;
        //判断容器大小,是否溢出,过程类似于ArrayLIst
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

3、Vector与ArrayList的区别

(1)同步性:

        Vector集合线程安全,效率低;ArrayList线程不安全,效率高

(2)数据增长规则(容器扩张规则)

         Vector与ArrayList的默认容器大小均为10,可自定义容器大小,不同之处在于:当增加的元素超出容量本身的大小时,集合容器大小自动动态的增长,Vector容器增加为原来的一倍,ArrayList容器增加为原来的一半

4、ArrayList,Vector, LinkedList的存储性能和特性

         ArrayListVector都是使用数组方式存储数据,此数组元素数大于实际存储的数据便自动扩容,以增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。

LinkedList也是线程不安全的,LinkedList提供了一些方法,使得LinkedList可以被当作堆栈和队列来使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值