`
qq7689791
  • 浏览: 9532 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java源码分析之List接口以及ArrayList、LinkedList、Stack、Vector等实现类

 
阅读更多

讲解jdk源码中List接口之前我们先来看一个模式,迭代器设计模式。

        迭代器设计模式主要是为了对容器提供统一的遍历接口,对于不同的数据结构的遍历方式由不同的iterator实现类所实现,而且也对原始数据进行了封装,不至于在用户使用时暴漏内部细节,类图如下。

 上面图中的各个类其实就是jdk中Collection容器对迭代器设计模式的一个实现,Itr是AbstractList的一个内部类,内部类的好处就是它可以直接访问AbstractList中的数据,Itr类实现了对元数据的遍历,部分代码如下。

public boolean hasNext() {
    return cursor != size();
}

public E next() {
    checkForComodification();
    try {
        E next = get(cursor);
        lastRet = cursor++;
        return next;
    } catch (IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
    }
}

        java中的List接口以及实现类,类图如下:

List中主要有2种数据结构的实现,一种是数组,另一种是链表。

    数组的实现有ArrayList、Vector、Stack、CopyOnWriteArrayList他们都继承了AbstractList,AbstractList实现了List中的部分接口,并且实现了数组结构的遍历,也就是上边说到的迭代器设计模式中Iterator部分,Stack实现了一个LIFO,Vector实现了线程安全,CopyOnWriteArrayList则是线程安全的一个变体,读的操作没有锁性能会更好,而写的时候存在锁并且在写的时候copy元数据,在新的数据上做修改,然后在同步回元数据,从而实现了在遍历的时候可以对其进行修改而不会抛出CurrentModificationException异常。基于数组实现的容器都实现了RandomAccess接口,这是一个空接口,实现了这个接口的类代表支持随机访问,而支持随机访问的类在遍历时正如RandomAccess类中描述的那样,上面的遍历方式性能会好于下面的遍历方式如下:

 * <pre>
 *     for (int i=0, n=list.size(); i &lt; n; i++)
 *         list.get(i);
 * </pre>
 * runs faster than this loop:
 * <pre>
 *     for (Iterator i=list.iterator(); i.hasNext(); )
 *         i.next();
 * </pre>

 

    链表的实现只有LinkedList。


    这里我们主要讲解ArrayList和LinkedList,首先看ArrayList,它的类声明如下:

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

 

他实现了RandomAccess支持随机访问,因为底层是数组嘛,知道下标访问速度是非常快的哈,并且实现了Serializable接口,代表这个类可以序列化以及反序列化,Cloneable则代表这个类可以被克隆,这个克隆啊又涉及到原型设计模式,原型涉及模式分为深克隆和浅克隆,有兴趣的朋友可以自己了解下本节不做讲解。

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer.
     */
    private transient Object[] elementData;

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

 

ArrayList中只有这2个成员变量,elementData则是用来存放具体数据的,size则用来标记数组实际大小,但是这里elementData为什么被transient修饰呢,被transient修饰则代表在序列化时会忽略elementData,难道elementData就不序列化了吗,并不是,而是ArrayList重写了writeObject方法,因为elementData每次满的时候都会扩充,会存在NULL没有使用的元素,所以重写了writeObject方法在序列化时只写入elementData的0到size实际使用的的数据。

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

 add添加元素时首先调用了ensureCapacity方法,这个方法会进行判断当前数组容量是否小于size+1,如果小于则扩充,扩充是调用的system.arraycopy的native方法来将数组copy到另一个扩充之后的数组中,然后把要添加的数据存放在elementData中。其余的方法和类都比较简单类似就不在说了。

    LinkedList底层使用Entry类来存放数据元素。

private static class Entry<E> {
    E element;
    Entry<E> next;
    Entry<E> previous;

    Entry(E element, Entry<E> next, Entry<E> previous) {
        this.element = element;
        this.next = next;
        this.previous = previous;
    }
}

 链表,就是手拉手,通过一个元素可以知道上一个元素和下一个元素,这个链表不了解的话可以先学习下数据结构这里就不在多说了,链表的遍历方式实现和数组是不一样的,

 

    private class ListItr implements ListIterator<E> {
	private Entry<E> lastReturned = header;
	private Entry<E> next;
	private int nextIndex;
	private int expectedModCount = modCount;

	ListItr(int index) {
	    if (index < 0 || index > size)
		throw new IndexOutOfBoundsException("Index: "+index+
						    ", Size: "+size);
	    if (index < (size >> 1)) {
		next = header.next;
		for (nextIndex=0; nextIndex<index; nextIndex++)
		    next = next.next;
	    } else {
		next = header;
		for (nextIndex=size; nextIndex>index; nextIndex--)
		    next = next.previous;
	    }
	}

	public boolean hasNext() {
	    return nextIndex != size;
	}

	public E next() {
	    checkForComodification();
	    if (nextIndex == size)
		throw new NoSuchElementException();

	    lastReturned = next;
	    next = next.next;
	    nextIndex++;
	    return lastReturned.element;
	}

 构造方法中初始化了next的值,if(int < (size >> 1))这里介绍下>>和>>>符号,>>代表向右移位,例如3>>1则代表二进制0011向右移动1位则是0001最终结果就是1,8>>>3代表8除以2的3次方最终结果则是1。

这里的if(int < (size >> 1))主要是为了判断这个元素时在前半段还是在后半段size >> 1相当于size/2,主要是为了更快的定位链表中第index元素的位置,不用从头遍历,这就是迭代器设计模式的好处,隐藏了内部实现的细节,对不同的数据结构提供了统一的迭代接口,就到这吧!

  • 大小: 15.4 KB
  • 大小: 6.3 KB
分享到:
评论

相关推荐

    java8源码-csn-list:ArrayList、LinkedList、Vector、Stack源码分析

    List相关实现类的源码解析(JDK1.8) 2018.9.22- List的架构图 ArrayList 继承关系: ArrayList -&gt; AbstractList 实现 List接口 ArrayList 是一个数组队列,相当于 动态数组。与Java中的数组相比,它的容量能动态...

    Java 基础核心总结 +经典算法大全.rar

    ArrayList Vector LinkedList 类Stack HashSet TreeSet LinkedHashSet 类 PriorityQueue HashMap TreeMap 类 LinkedHashMap 类 Hashtable 类IdentityHashMap 类WeakHashMap 类 Collections 类集合实现类特征图 泛形 ...

    JavaSE 笔试 精华

    Collection List LinkedList ArrayList Vector Stack Set HashSet Map HashMap Dictionary Hashtable Comparetor 2. Vector和ArrayList、LinkedList区别? Hashtable 和 HashMap之间的区别 LinkedList内部以链表...

    java面试宝典

    67、说出ArrayList,Vector, LinkedList的存储性能和特性 17 68、java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类? 17 69、文件读写的基本类 17 70、多线程有几种实现...

    浅谈java集合类以及示例

    聊一聊java 的集合类 概述 Java中集合分为两种类型 ...List下常用的有ArrayList、LinkedList、Vector、Stack Set下常用的有HashSet、TreeSet Queue又有Deque、Stack、LinkedList SET ​ 无序不可重复,没有下标。规定S

    List效率的比较

    让Stack 来做List 的事可以,不过语义上Stack 不应该做过多的List 的事情;  7.在排序中,ArrayList 具有最好的性能,TreeList 平均性能也不错,LinkedList 的排序效率受元素初始状态的影响很大。  8.各种List 间...

    集合效率不完全皮恩车

    AttributeList , ArrayList , CopyOnWriteArrayList , LinkedList RoleList , RoleUnresolvedList , Stack Vector Set接口 ConcurrentSkipListSet , CopyOnWriteArraySet , EnumSet…, HashSet JobStateReasons , ...

    超全Java集合框架讲解.md

    超全Java集合框架讲解 ... - List 接口 - AbstractList 和 AbstractSequentialList - Vector - Stack - ArrayList - LinkedList - Queue接口 - Deque 接口 - AbstractQueue 抽象类 - Lin

    Java集合总结.txt

    单个集合的学习路线:使用-&gt;做实验-&gt;画图-&gt;分析源码 集合:大小可变的序列,只能存放对象 集合和数组的区别: 1.集合是大小可变的序列,数组在声明后,长度不可变 2.数组只能存放声明时指定的一种数据类型,集合...

    了解Collection 和 Collections

    java.util.Collection 是一个集合接口(集合类的一个顶级接口)。 它提供了对集合对象进行基本操作的通用接口方法。 Collection接口在Java 类库中有很多具体的实现。 Collection接口的意义是为各种具体的集合提供了...

    java 面试题 总结

     Collection是集合类的上级接口,继承与他的接口主要有Set 和List. Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。 10、&和&&的区别。 &是位运算符...

    跟汤老师学Java(第13季):集合

    4.List:ArrayList、LinkedList、Vector、Stack 5.Set:HashSet、TreeSet 6.Map:HashMap、Hashtable、Properties 7.Collections工具类 教学全程采用笔记+代码案例的形式讲解,通俗易懂!!!

    java面试宝典2012版.pdf

    64、说出ArrayList,Vector, LinkedList的存储性能和特性 65、去掉一个Vector集合中重复的元素 66、Collection 和 Collections的区别。 67、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是...

    Java面试宝典-经典

    64、说出ArrayList,Vector, LinkedList的存储性能和特性 46 65、去掉一个Vector集合中重复的元素 46 66、Collection 和 Collections的区别。 47 67、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用...

    Java面试宝典2010版

    64、说出ArrayList,Vector, LinkedList的存储性能和特性 46 65、去掉一个Vector集合中重复的元素 46 66、Collection 和 Collections的区别。 47 67、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用...

    java面试题大全(2012版)

    64、说出ArrayList,Vector, LinkedList的存储性能和特性 46 65、去掉一个Vector集合中重复的元素 46 66、Collection 和 Collections的区别。 47 67、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用...

    超级有影响力霸气的Java面试题大全文档

     Collection是集合类的上级接口,继承与他的接口主要有Set 和List. Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。 13、&和&&的区别。 &是位运算符...

    最新Java面试宝典pdf版

    64、说出ArrayList,Vector, LinkedList的存储性能和特性 46 65、去掉一个Vector集合中重复的元素 46 66、Collection 和 Collections的区别。 47 67、Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用...

Global site tag (gtag.js) - Google Analytics