List接口的一些列实现中,最常用最重要的就是这三个:ArrayList、Vector、LinkedList。这里我就基于JDK1.7来看一下源码。

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable

 从这三个类定义就可以看出一些信息:

  • ArrayList、Vector继承了AbstractList这个抽象类,LinkedList继承了AbstractSequentialList
    这个抽象类,AbstractSequentialList 也是继承AbstractList,只不过它实现了get(int index)、
    set(int index, E element)、add(int index, E element) 和 remove(int index)这些骨干性函数,降低了List接口的复杂度;
  • ArrayList和Vector都实现了RandomAccess接口,而LinkedList没有,这是什么意思呢?在JDK中,RandomAccess接口是一个空接口,
    所以它没有实际意义,就是一个标记,标记这个类支持快速随机访问,所以,arrayList和vector是支持随机访问的,但是LinkedList不支持;
  • serializbale接口表名,他们都支持序列化。
      

 在这三个List实现类里面:  

  1. ArrayList和Vector使用了数组的实现,相当于封装了对数组的操作。这也正是他们能够支持快速随机访问的原因,
    在JDK中所有基于数组实现的数据结构都能够支持快速随机访问。ArrayList和Vector的实现上几乎都使用了相同的算法,
    他们的主要区别就是ArrayList没有对任何一个方法做同步,所以不是线程安全的;而Vector中大部分方法都做了线程同步,是线程安全的。
  2. LinkedList使用的是非循环双向链表的数据结构(这是JDK1.7更新部分,LinkedList在1.7之前都是循环双向链表)
    由于是基于链表的,所以是没法实现随机访问的,只能顺序访问,这也正式它没有实现RandomAccess接口的原因。

  ArrayList和Vector方法实现基本一样,所以这里我就拿ArrayList和LinkedList来做对比。

一、add方法

  1. ArrayList实现add

         public boolean add(E e) {
    ensureCapacityInternal(size + 1); // Increments modCount!!
    elementData[size++] = e;
    return true;
    } private void ensureCapacityInternal(int minCapacity) {
    if (elementData == EMPTY_ELEMENTDATA) {
    minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    } ensureExplicitCapacity(minCapacity);
    } private void ensureExplicitCapacity(int minCapacity) {
    modCount++; // 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 + (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);
    }

    第2行,如果数组空间不够,实现数组动态扩容,动态扩容在grow方法实现,第11行,JDK利用移位运算符进行扩容计算,>>1右移一位表示除2,所以newCapacity就是扩容为原来的1.5倍。(PS:JDK1.7中第11行是移位运算,而在JDK1.6中第11行是直接除2,所以说JDK1.7相比于JDK1.6代码优化了),然后数组空间足够大,然后在数组末尾增加元素并且通过后++完成add元素。

  2. LinkedList实现add
         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++;
    }

    代码中可以看到,LinkedList基于链表的,不需要扩容,直接把元素加到链表最后,把新元素的前节点指向之前的last元素后节点就ok了。

  二、get方法

  1. ArrayList实现get

         public E get(int index) {
    rangeCheck(index); return elementData(index);
    } E elementData(int index) {
    return (E) elementData[index];
    }

    ArrayList的get方法比较方便,通过数组下标能够直接找到数据返回。

  2. LinkedList实现get
         public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
    } Node<E> node(int index) {
    // assert isElementIndex(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;
    }
    }

    ArrayList的get方法需要遍历到具体位置,获得数据返回,这里为了提高效率,需要根据获取的位置判断是从头还是从尾开始遍历,将index与长度size的一半比较,如果index<size/2,就只从位置0往后遍历到位置index处,而如果index>size/2,就只从位置size往前遍历到位置index处即可。

  三、remove方法

  1. ArrayList实现remove

         public E remove(int index) {
    rangeCheck(index); modCount++;
    E oldValue = elementData(index); int numMoved = size - index - 1;
    if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
    numMoved);
    elementData[--size] = null; // clear to let GC do its work return oldValue;
    } public boolean remove(Object o) {
    if (o == null) {
    for (int index = 0; index < size; index++)
    if (elementData[index] == null) {
    fastRemove(index);
    return true;
    }
    } else {
    for (int index = 0; index < size; index++)
    if (o.equals(elementData[index])) {
    fastRemove(index);
    return true;
    }
    }
    return false;
    } private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
    numMoved);
    elementData[--size] = null; // clear to let GC do its work
    }

    ArrayList实现remove(int)和remove(Object)两种方式,通过System的arrayCopy方法实现元素的移动(本质上是数组的复制),remove(Object)方法实际上是先找到需要删除元素的下标,然后在实现删除功能,实际和remove(int)一样。

  2. LinkedList实现remove
         public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
    } public boolean remove(Object o) {
    if (o == null) {
    for (Node<E> x = first; x != null; x = x.next) {
    if (x.item == null) {
    unlink(x);
    return true;
    }
    }
    } else {
    for (Node<E> x = first; x != null; x = x.next) {
    if (o.equals(x.item)) {
    unlink(x);
    return true;
    }
    }
    }
    return false;
    } E unlink(Node<E> x) {
    // assert x != null;
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev; if (prev == null) {
    first = next;
    } else {
    prev.next = next;
    x.prev = null;
    } if (next == null) {
    last = prev;
    } else {
    next.prev = prev;
    x.next = null;
    } x.item = null;
    size--;
    modCount++;
    return element;
    }

    LinkedList实现remove(int)和remove(Object),不管是根据下标删除还是根据Object删除,都是先找到对应的Node,然后在删除,对应的上下数据节点改变。

  四、总结

  1. 对于查找get方法,ArrayList的效率是要比LinkedList高的,原因也是ArrayList是基于数组的,直接通过下标能找到,LinkedList则需要遍历到具体位置。
  2. 增加add方法和删除remove方法,虽说链表的增加和删除效率比数组高,但是这也不是绝对,看具体情况,有几种极端情况,一种是在LinkedList和ArrayList的首位增加和删除,这种LinkedList效率好一点,如果在中间处增加和删除,这种的话ArrayList效率好一点,所以说增加add方法和删除remove方法说不上哪个效率高,这要看具体情况分析。

ArrayList、Vector、LinkedList源码的更多相关文章

  1. java基础解析系列(十)---ArrayList和LinkedList源码及使用分析

    java基础解析系列(十)---ArrayList和LinkedList源码及使用分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder jav ...

  2. ArrayList和LinkedList源码

    1 ArrayList 1.1 父类 java.lang.Object 继承者 java.util.AbstractCollection<E> 继承者 java.util.Abstract ...

  3. ArrayList 和 LinkedList 源码分析

    List 表示的就是线性表,是具有相同特性的数据元素的有限序列.它主要有两种存储结构,顺序存储和链式存储,分别对应着 ArrayList 和 LinkedList 的实现,接下来以 jdk7 代码为例 ...

  4. ArrayList & Vector的源码实现

    #ArrayList & Vector #####前言: 本来按照计划,ArrayList和Vector是分开讲的,但是当我阅读了ArrayList和Vector的源码以后,我就改变了注意,把 ...

  5. List中的ArrayList和LinkedList源码分析

    ​ List是在面试中经常会问的一点,在我们面试中知道的仅仅是List是单列集合Collection下的一个实现类, List的实现接口又有几个,一个是ArrayList,还有一个是LinkedLis ...

  6. ArrayList和LinkedList源码分析

    ArrayList 非线程安全 ArrayList内部是以数组存储元素的.类有以下变量: /*来自于超类AbstractList,使用迭代器时可以通过该值判断集合是否被修改*/ protected t ...

  7. ArrayList、LinkedList和Vector的源码解析,带你走近List的世界

    java.util.List接口是Java Collections Framework的一个重要组成部分,List接口的架构图如下: 本文将通过剖析List接口的三个实现类——ArrayList.Li ...

  8. Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  9. Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例

    概要 上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解Arra ...

  10. 给jdk写注释系列之jdk1.6容器(2)-LinkedList源码解析

    LinkedList是基于链表结构的一种List,在分析LinkedList源码前有必要对链表结构进行说明.   1.链表的概念      链表是由一系列非连续的节点组成的存储结构,简单分下类的话,链 ...

随机推荐

  1. Python 【第六章】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy

    Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...

  2. Django models 操作高级补充

    Django models 操作高级补充 字段参数补充: 外键 约束取消 ..... ORM中原生SQL写法: raw connection extra

  3. html中用div代替textarea实现输入框高度随输入内容变化

    项目中的需求:留言栏输入高度变化,超过1行时,自动伸展,超过4行后,不再伸展.主要思想是利用最小高度和最大高度,再加上overflow来实现,到了最大高度,文字不会溢出而是隐藏.根据文本框中字体的大小 ...

  4. iOS - drawRect致内存增加

    GPU VS CPU iOS - 软件绘图 自定义"斑马线背景"View,重写drawRect绘制斑马线: ⚠️ 仅仅添加这一个View,内存就比正常增加了3-5M之间. 测试源代 ...

  5. Jquery实现特效滑动菜单栏

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. CMake

    使用CMake编译跨平台静态库 http://www.tuicool.com/articles/3uu2Yj cmake命令 安装.用法简介 https://fukun.org/archives/04 ...

  7. SQL 归来

    1. PL/SQL 转义 select order#, ………  from **** select col1 from A where col2 like '%\_keywors%' escape ' ...

  8. linux常见命令总结

    日志文件说明 /var/log/message 系统启动后的信息和错误日志,是Red Hat最常用的日志之一 /var/log/secure 与系统安全相关的日志信息 /var/log/maillog ...

  9. 使用MyEclipse 9.0 创建 struts2 的HelloWorld 工程

    作为眼高手低的典范,必须痛改前非,好好动手多做开发! 本文是struts2的入门指导,权当笔记! 在MyEclipse中,配置Apache tomcat 7.x 服务器 创建新的Web project ...

  10. C#语言之“中英文混合字符串对齐”的方法

    参考自:(1)http://www.cnblogs.com/cnluoke/articles/1213398.html (2)http://www.cnblogs.com/sql4me/archive ...