ArrayList、Vector和LinkedList比较

ArrayList、Vector和LinkedList都是Java中的集合类,各有特点。ArrayList和Vector基于数组实现,适合快速查找,但插入和删除操作相对较慢,尤其是当需要在中间位置插入或删除时。Vector操作是线程安全的,而ArrayList不是。LinkedList基于链表,插入和删除高效,但查找效率相对较低,因为需要遍历。因此,选择哪种集合取决于具体应用场景。
摘要由CSDN通过智能技术生成
  • 继承与实现接口:

    • ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    • Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    • LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
      从上可以看出,ArrayList与Vector都继承了AbstractList并实现了List等接口,而LinkedList继承了AbstractSequentialList,实现了List与Deque接口,再深究AbstractSequentialList同样继承了AbstractList,所有他们三个有一定的共通性,当然ArrayList也Vector更接近。而LinkedList独有的实现Deque接口,为它带来了一些链表所有的void addFirst(E e)void addLast(E e)等方法。
  • 添加元素:

    • ArrayList:可插入空数据,相当于动态数据,其中最重要的两个属性分别是: elementData 数组,以及 size 大小。
      //调用 add() 方法
      public boolean add(E e) {
      	//首先进行扩容校验
          ensureCapacityInternal(size + 1);
          //将新插入的值放在数组的尾部,并且size加1
          elementData[size++] = e;
          return true;
      }
      
      //调用 add(index,e) 在指定位置添加
      public void add(int index, E element) {
      	//校验插入数据的index是否合法
          rangeCheckForAdd(index);
          //进行扩容校验
          ensureCapacityInternal(size + 1);
          //对数据进行复制,目的是把 index 位置空出来放本次插入的数据,并将后面的数据向后移动一个位置
          System.arraycopy(elementData, index, elementData, index + 1,
                           size - index);
          elementData[index] = element;
          size++;
      }
      //扩容校验最终的调用
      private void grow(int minCapacity) {
          int oldCapacity = elementData.length;
          int newCapacity = oldCapacity + (oldCapacity >> 1);
          if (newCapacity - minCapacity < 0)
              newCapacity = minCapacity;
          if (newCapacity - MAX_ARRAY_SIZE > 0)
              newCapacity = hugeCapacity(minCapacity);
          elementData = Arrays.copyOf(elementData, newCapacity);
      }
      
      在ArrayList添加数据时,当长度不够需要进行扩容时,都需要将保存数据数组进行一次复制,以及在指定位置插入数据时。
    • Vector
      //调用 add() 方法
      public synchronized boolean add(E e) {
          modCount++;
          ensureCapacityHelper(elementCount + 1);
          elementData[elementCount++] = e;
          return true;
      }
      
      //调用 add(index,e) 在指定位置添加
      public void add(int index, E element) {
          insertElementAt(element, index);
      }
      public synchronized void insertElementAt(E obj, int index) {
          modCount++;
          if (index > elementCount) {
              throw new ArrayIndexOutOfBoundsException(index
                                                       + " > " + elementCount);
          }
          ensureCapacityHelper(elementCount + 1);
          System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
          elementData[index] = obj;
          elementCount++;
      }
      
      Vector插入数据的方式与ArrayList是一样的,与ArrayList的区别在于,Vector插入数据是同步执行的。
    • LinkedList: 底层是基于双向链表实现的
      //插入数据
      public boolean add(E e) {
          linkLast(e);
          return true;
      }
      void linkLast(E e) {
          final Node<E> l = last;
          final Node<E> newNode = new Node<>(l, e, null);
          last = newNode;
          if (l == null)
              first = newNode;
          else
              l.next = newNode;
          size++;
          modCount++;
      }
      
      每次插入数据都只是移动指针。

总结:从上可以看出,在使用ArrayList和Vector时,我们尽量指定长度已经减少指定index插入方式,减少扩容操作,由于他两保存数据的是数值,取数据的效率很高,而且Vector的插入数据是同步执行的,所以我们可以认为Vector是线程安全的,LinkedList插入数据不像ArrayList与Vector在进行扩容时,需要复制整个保存数据的数组,所以效率高,难道LinkedList就十分完美了么?NO、NO、NO,我们来看看LinkedList的查询:

public E get(int index) {
	//进行下标验证
    checkElementIndex(index);
    return node(index).item;
}
Node<E> node(int index) {
	// assert isElementIndex(index);
	//利用了双向链表的特性,如果index离链表头比较近,就从节点头部遍历。否则就从节点尾部开始遍历
	if (index < (size >> 1)) {
	    Node<E> x = first;
	    for (int i = 0; i < index; i++)
	        x = x.next;
	    return x;
	} else {
	    Node<E> x = last;
	    for (int i = size - 1; i > index; i--)
	        x = x.prev;
	    return x;
	}
}

当LinkedList存入的数据够大,而要取靠近中间的值时,迭代数据取值的效率较之另两个就有点低了,所以LinkedList 插入,删除都是移动指针效率很高,但是查找需要进行遍历查询,效率较低。由于LinkedList保存了第一个元素和最后一个元素的值,所以取这两个数据的效率还是很好的。

更多文章:
CSDN博客
简书博客
公众号:代码小搬运
代码小搬运.jpg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值