`
xtuali
  • 浏览: 11925 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java源码分析之LinkedList

阅读更多

 

LinkedList源码分析

1. 数据结构

1.1. 单链表

1.2. 双向链表

LinkedList采用的是双向链表模式,而每一个节点就是一个LinkedList类的一个私有静态的内部类EntryEntry含有三个成员:E element (E就是申明变量时需要的泛型参数)Entry nextEntry previous

2. 类的申明

 

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

继承至AbstractSequentialList(此类提供了List接口的骨干实现,从而最大限度减少了实现受“连续访问”数据存储支持的此接口的所需工作)

在实现的接口中Cloneable表示LinkedList能够被复制,实现java.io.Serializable表示此类能被序列化

3. 成员变量分析

 

private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;
 

关键字transient的作用是表示一个域不是该对象串行化(序列化)的一部分,当这个对象串行化的时候transient申明的变量不包括在串行化的表示中,而非transient的变量会被包括进去。

4. 构造函数分析

 

 /**
     * Constructs an empty list.	//构造一个空链表
     */
    public LinkedList() {
        header.next = header.previous = header;
    }
    public LinkedList(Collection<? extends E> c) {
	this();		//首先构造一个空链表
	addAll(c);	//将初始化的Collection加入到此链表中
  }
     

5. 成员方法分析

5.1. 增加元素

LinkedList提供像链表中增加元素的方法有很多,例如:add(e)add(int,e)addAll(int,Collection)addAll(Collection),只需分析add(int,e)以及addAll(int,Collection)即可,其余的都是基于这两个函数实现的。

5.1.1. Add(int,e)

 

public void add(int index, E element) {
        addBefore(element, (index==size ? header : entry(index)));
}

entry(index)将在链表中返回位置是index的链表元素,因为链表不像数组可以随机读取,对于链表来说得到某一位置的元素只能一个一个遍历得到位置,然后将前后位置元素的索引改变,而LinkedList是一个双向链表,在寻找插入位置的时候,会判断是位于前半部分还是后半部分,如果是前半部分则从第一个往后遍历,如果是后半部分则有最后一个往前遍历,然后将位置属于index的元素返回。

addBefore(E e,Entry entry)

 

private Entry<E> addBefore(E e, Entry<E> entry) {
    //将newEntry的next指向entry,previous指向尾部entry的尾部
    Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
//将entry前面元素的后驱指向newEntry
    newEntry.previous.next = newEntry;
    //将entry元素的前驱指向newEntry
    newEntry.next.previous = newEntry;
size++;
    modCount++;
    return newEntry;
}
 

对于add(E e)则是调用方法addBefore(e,header)

5.1.2. addAll(int,Collection)

 

public boolean addAll(int index, Collection<? extends E> c) {
    //验证链表的长度与要插入的位置的大小
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index+
                                                ", Size: "+size);
        //将要插入的Collection转换成数组
        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew==0)
            return false;
        modCount++;//是AbstractList中得一个字段,用来记录list结构变化的次数
        //得到index位置的entry
        Entry<E> successor = (index==size ? header : entry(index));
        Entry<E> predecessor = successor.previous;
        //依次将c插入原链表中
        for (int i=0; i<numNew; i++) {
            Entry<E> e = new Entry<E>((E)a[i], successor, predecessor);
            predecessor.next = e;
            predecessor = e;
        }
        successor.previous = predecessor;
        size += numNew;
        return true;
    }
 

5.2. 删除元素

仅分析remove(Entry<E> e),因为其余有关删除的操作都是基于这个函数实现的

 

private E remove(Entry<E> e) {
	if (e == header)
		throw new NoSuchElementException();

	E result = e.element;
	//将要删除的元素的前面元素的后驱指向删除元素的后驱
	e.previous.next = e.next;		
       //将要删除的元素的后面元素的前驱指向删除元素的前驱
	e.next.previous = e.previous;
	e.next = e.previous = null;
	e.element = null;
	size--;
	modCount++;
	return result;
}
   

6. 迭代器

ArrayList不同的是LinkedList实现了自己的迭代器,实现了ListIterator接口,ListIterator接口继承至Iterator接口,LinkedList,没有直接使用AbstractList虚类中的实现,LinkedList内部自定义了一个内部类ListItr,该类实现了ListIterator接口,专门对LinkedList进行迭代,但是要注意的是因为ArrayListLinkedList的迭代器的功能和特点都是一样的,所以符合ArrayList迭代器的特点都符合LinkedList的特点。AbstractList实现了两个迭代器分别是Itr以及ListItr,其中ListItr更适用于LinkedList,因为LinkedList是一个双向链表。以下是LinkedList中的:ListIterator的实现:

 

private class LinkedList implements ListIterator<E> {
//最近一次next或previous操作所返回的元素,初始为头结点,表示链表的开始与结尾
    private Entry<E> lastReturned = header;
    //next操作所返回的节点
    private Entry<E> next;
    //记录当前next指向的entry的位置,与next保持一致
    private int nextIndex;
    //检测外界是否改变结合的结构
    private int expectedModCount = modCount;
    //得到第index位置的元素(entry)
    ListItr(int index) {
       //此方法运行完毕next指向的就是index位置的元素
        if (index < 0 || index > size)
       throw new IndexOutOfBoundsException("Index: "+index+
                         ", Size: "+size);
        if (index < (size >> 1)) {   //当index小于size的一半是在前半部找
           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;
//执行next的结果是next与lastReturned不相等
        nextIndex++;
        return lastReturned.element;
    }
 
    public boolean hasPrevious() {
        return nextIndex != 0;
    }
 
    public E previous() {
        if (nextIndex == 0)
       throw new NoSuchElementException();
//执行previous的结果是next与lastReturned不相等
        lastReturned = next = next.previous;
        nextIndex--;
        checkForComodification();
        return lastReturned.element;
    }
 
    public int nextIndex() {
        return nextIndex;
    }
 
    public int previousIndex() {
        return nextIndex-1;
    }
 
    public void remove() {
            checkForComodification();
            Entry<E> lastNext = lastReturned.next;
            try {
                LinkedList.this.remove(lastReturned);
            } catch (NoSuchElementException e) {
                throw new IllegalStateException();
            }
        if (next==lastReturned)
             next = lastNext;
        else
           nextIndex--;
       //每次remove操作之后就会将lastReturned指向header
        lastReturned = header;  
        expectedModCount++;
    }
 
    public void set(E e) {
        if (lastReturned == header)
            throw new IllegalStateException();
        checkForComodification();
        lastReturned.element = e;
    }
 
    public void add(E e) {
        checkForComodification();
//每次add操作之后就会将lastReturned指向header
        lastReturned = header;
        addBefore(e, next);
        nextIndex++;
        expectedModCount++;
    }
 
    final void checkForComodification() {
        if (modCount != expectedModCount)
       throw new ConcurrentModificationException();
    }
}
 

从源码中可以看出:

1.  刚实例化的迭代器lastReturned是指向header节点的,是不能马上进行删除跟修改操作的,需要首先进行后移或者前移操作;

2.  只要lastReturned指向header是不能进行删除以及修改操作的,所以以下成立:

 可以对迭代器进行连续的添加或者修改,但是不能进行连续的删除,因为删除后lastReturned指向header是不能再删除的;

 进行添加操作后不能立刻进行删除或者修改操作;

 进行删除操作操作后可以进行添加操作,但是不能进行修改操作;

 进行修改后是可以进行删除和增加操作的;

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics