LinkedList源码分析
1. 数据结构
1.1. 单链表
1.2. 双向链表
LinkedList采用的是双向链表模式,而每一个节点就是一个LinkedList类的一个私有静态的内部类Entry,Entry含有三个成员:E element (E就是申明变量时需要的泛型参数)、Entry next、Entry
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进行迭代,但是要注意的是因为ArrayList与LinkedList的迭代器的功能和特点都是一样的,所以符合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是不能再删除的;
进行添加操作后不能立刻进行删除或者修改操作;
进行删除操作操作后可以进行添加操作,但是不能进行修改操作;
进行修改后是可以进行删除和增加操作的;
分享到:
相关推荐
在Java编程语言中,LinkedList是一个常用的集合类,它实现了List接口,同时也提供了双向链表的实现...在阅读和分析给定的Queue.java和Stack.java文件时,可以从实现原理、方法调用、线程安全等方面进行深入学习和理解。
Java集合系列之LinkedList源码分析 概述: 本文详细介绍了Java集合系列之LinkedList的源码分析,主要介绍了LinkedList的底层实现、成员变量、构造器、增删改查方法等。LinkedList是一种基于双向链表的数据结构,...
Java源码分析Iterable Java源码分析Iterable是Java编程语言中一个基础组件的源码分析,Iterable是一个接口,它允许对象被迭代,例如foreach循环中的数组或集合。了解Iterable的源码,可以帮助开发者更好地理解Java...
**源码分析** 深入研究这些类的源码,可以帮助我们理解它们是如何在内存中组织数据以及如何执行各种操作的。例如,`HashMap`的哈希函数如何计算元素的桶位置,`ArrayList`如何调整其容量,以及`LinkedList`如何通过...
能学到什么:ArrayList的源码分析,自动扩容和自动缩容的源码分析,相关参数的深度解析,从是什么,为什么,怎么做三个角度进行讲解,用通俗易懂的白话进行介绍,LinkedList和Vector以及ArrayList的区别以及使用场景...
Java源码大全是一个集合了各种Java编程基础知识和经典算法的资源包,对于Java初学者以及有一定经验的开发者来说,都是一个宝贵的参考资料。这个压缩包涵盖了Java语言的不同方面,旨在帮助学习者深入理解Java编程的...
计算机后端-Java-Java核心基础-第24章 集合01 15. LinkedList的源码分析.avi
Java集合框架源码分析 Java集合框架是Java语言中一个非常重要的组件,提供了多种数据结构和算法来存储和操作数据。在Java集合框架中,LinkedList、ArrayList、HashMap、TreeMap等都是非常常用的数据结构。本文将对...
Java集合框架是Java编程语言中非常重要的组成部分,它为Java开发者提供了大量用于存储数据的结构。Java集合框架主要包括两大类,单列集合和双列集合。单列集合中,Set接口的集合主要用于存储不重复的元素,而List...
### LinkedList部分源码解析 #### 一、简介 `LinkedList`是Java集合框架的一个重要组成部分,它基于双向链表实现,既支持`List`接口也实现了`Deque`接口,因此可以作为列表、栈或者队列使用。双向链表的每个节点...
Java源码是学习编程语言的重要资源,特别是对于初学者来说,通过阅读和分析源代码,可以深入理解语言的特性和编程技巧。这个压缩包包含了140个经典的Java源代码程序,涵盖了各种基础到进阶的编程概念。下面,我们将...
《深入解析CoreJava源码》 Java语言作为世界上最流行的编程语言之一,其强大的跨平台能力和丰富的类库使得它在各种领域都有广泛的应用。对于初学者和有经验的开发者来说,理解Java的核心概念和源码是提升技能的关键...
《LinkedList源码解析》 LinkedList是Java集合框架中的一员,它是AbstractSequentialList的子类,同时也实现了List、Deque和Cloneable、Serializable接口。LinkedList作为双向链表,支持快速的添加、删除元素,尤其...
Java API中提供了链表的Java实现—LinkedList下。LinkedList是通过节点的连接实现链表的数据结构,向linkedList中插入或删除元素的速度是特别快,而随机访问的速度相对较慢,这个是由于链表本身的性质造成的,在链表...
"140个java源码实例源码整理"这个资源集合显然提供了大量的Java编程示例,可以帮助初学者和经验丰富的开发者深入理解Java的核心概念以及实际应用。 首先,Java源码实例是学习编程的重要途径,它们提供了实际的代码...
这篇博客文章《Java rt.jar 源码分析》可能探讨了以下几个关键知识点: 1. **Java基础类库**:rt.jar中的类库涵盖了Java语言的核心功能,包括对象模型、基本类型、集合框架、多线程、网络编程、I/O流、反射、异常...
Java源码集合是一个珍贵的学习资源,它包含了从大一开始积累的31个不同Java项目,适合于课程设计、毕业设计以及个人技能提升。这个压缩包是开发者或学习者的一个宝库,提供了各种类型的代码示例,有助于深入理解Java...
《LinkedList源码学习分析》 LinkedList作为Java集合框架中的一员,是基于链表数据结构实现的线程不安全容器。本文将深入探讨LinkedList的实现原理、核心方法的代码实现,并对比ArrayList,理解其特性和使用场景。 ...