一.LinkedList的内部数据结构

  LinkedList底层是一个链表的数据结构,采用的是双向链表,基本的Node数据结构代码如下:

private static class Node<E> {
E item; //节点放置的元素
Node<E> next; //下一节点
Node<E> prev; //上一结点 Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}

二.LinkedList的结点的常用操作

  在LinkedList实现List接口的一系列方法的时候,底层是通过一系列结点操作,完成对于LinkedList的方法的实现,操作代码如下:

    /**
* 将一个元素链接到链表的开头
*/
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
} /**
* 将元素e链接到链表的末端
*/
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++;
} /**
* 将一个元素链接到指定结点的前面
*/
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
} /**
* 将一个first结点解除关联
*/
private E unlinkFirst(Node<E> f) {
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
} /**
* 将一个last结点解除关联
*/
private E unlinkLast(Node<E> l) {
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
} /**
* 将一个结点x解除链接
*/
E unlink(Node<E> x) {
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的addAll方法

  插入一个Collection类型的元素的时候,需要先将Collection元素转化为数组类型的元素,然后对于数组中的每一个元素进行遍历,建立一系列结点,并将结点相互连接,然后与原来的结点相互连接.

public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false; Node<E> pred, succ;
if (index == size) { //表示在链表末尾添加
succ = null;
pred = last;
} else { //在链表中间添加
succ = node(index);//获取在当前索引位置的元素
pred = succ.prev;//pred--记录当前索引位置的元素的前面的一个元素
} for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null); //在当前索引位置的元素前面添加元素
if (pred == null) //前面没有元素,说明插入的节点是链表的第一个元素
first = newNode;
else //前面节点的next指向当前节点
pred.next = newNode;
pred = newNode; //pred指向当前节点为下一次赋值做准备
} if (succ == null) { //插入前,索引处没有元素
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
} size += numNew;
modCount++;
return true;
}

四.remove操作

  remove操作通过对于链表结点进行遍历,如果结点的元素等于参数的元素,则调用unlink方法,将结点的关系解除.

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;
}

五.clear方法

  通过对于链表的所有的元素进行遍历,并且将遍历到的元素的所有属性设为null,交给垃圾回收器处理.

public void clear() {
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}

六.get方法

  get方法是LinkedList获取某一索引处的元素的方法,由于链表的数据结构查询比较慢,因此通常不推荐对于LinkedList类型的数据结构调用一系列get方法.但是LinkedList数据结构本身对于get方法进行了优化,当索引大于中间索引的时候,从最后一个元素开始查询.当索引小于中间索引的时候,从第一个元素开始查询.

 public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int 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;
}
}

Java源码初学_LinkedList的更多相关文章

  1. Java源码初学_AbstractList&AbstractCollection

    一.AbstractCollection抽象类:(提供了Collection接口的骨干实现,以减少实现接口所需要的工作) 1.contains方法 contains方法,通过迭代器对于列表的每一个元素 ...

  2. Java源码初学_HashSet&LinkedHashSet

    一.概述 HashSet是建立在HashMap的基础上的,其内部存在指向一个HashMap对象的引用,操作HashSet实际上就是操作HashMap,而HashMap中所有键的值都指向一个叫做Dumm ...

  3. Java源码初学_LinkedHashMap

    一.概述: LinkedHashMap是HashMap的子类,它的基本操作与HashMap相同,与之不同的是,它可以实现按照插入顺序进行排序.也可以通过在构造函数中指定参数,按照访问顺序排序(Link ...

  4. Java源码初学_HashMap

    一.概念 HashMap的实例有两个参数影响其性能:初始容量和加载因子.容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量.加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度.当哈希表 ...

  5. Java源码初学_ArrayList

    一.ArrayList的构造器和构造方法 在ArrayList中定义了两个空数组,分别对应当指定默认构造方法时候,指向的数组已经给定容量,但是容量等于0的时候,指向的数组.此外在构造函数中传入Coll ...

  6. 如何阅读Java源码 阅读java的真实体会

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心.   说到技术基础,我打个比 ...

  7. Android反编译(一)之反编译JAVA源码

    Android反编译(一) 之反编译JAVA源码 [目录] 1.工具 2.反编译步骤 3.实例 4.装X技巧 1.工具 1).dex反编译JAR工具  dex2jar   http://code.go ...

  8. 如何阅读Java源码

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动.源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比方吧, ...

  9. Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库

    http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...

随机推荐

  1. hdwiki中插件开发指南

    插件就是为了满足个性化需求按照HDWiki插件开发规范编写的可插拔程序,虽然可以直接对HDWiki进行二次开发实现插件同样的功能,但是这样做势必影响到系统的升级和稳定性. 采用插件的方式,可以随时进行 ...

  2. 三种常见设计模式 - Factory

    创建型模型 一.简单工厂模式 靠 if else 或者 select case 等分支去控制不同对象的创建,难以维护 二.工厂方法模式  Factory 实现方式:将创建对象的方法定义成一个接口,通过 ...

  3. phpQuery—基于jQuery的PHP实现

    转载于:http://www.cnblogs.com/in-loading/archive/2012/04/11/2442697.html Query的选择器之强大是有目共睹的,phpQuery 让p ...

  4. linux文件描述符--转载

    转自:http://blog.csdn.net/cywosp/article/details/38965239 1. 概述     在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件.目录 ...

  5. acdeream Matrix Multiplication

    D - Matrix Multiplication Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/O ...

  6. POI 简单合并单元格

    public class MergedCells { /** 测试使用的POI版本是3.1 * @param args */ public static void main(String[] args ...

  7. 2016年10月22日 星期六 --出埃及记 Exodus 19:6

    2016年10月22日 星期六 --出埃及记 Exodus 19:6 you will be for me a kingdom of priests and a holy nation.' These ...

  8. 进程间通信之打开关闭一个exe文件

    一.打开 1.WinExec("F:\\QQ\\Bin\\QQ.exe",SW_SHOW); 注意:'\'需要改成'\\',阻塞 2. STARTUPINFO si; PROCES ...

  9. 把int放在一个char数组里(用于处理每一位数字)

    sprintf(): #include <stdio.h> void put_int_with_space(int v) {     char str[50];    //定义一个足够大的 ...

  10. JavaScript(1)

    JavaScript(1) 第一次见到JavaScript的时候,看到了熟悉的"Java",原来都是骗人的,李鬼不是李逵呀=.= 然而发现这个东西还是特别实用的,和Java比起来它 ...