JAVA基础 之LinkedList源码剖析

LinkedList源码剖析:

LinkedList是List的一个实现类,也是一个集合容器.它的底层实现是一个双链接列表实现,在查询上面比起ArrayList差了呢么一点,但是在增加和删除元素时的效率却远远高于ArrayList.我们来一探究竟

源码:

public class LinkedList<E>

extends AbstractSequentialList<E>

implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
}

LinkedList实现了List接口,Deque接口,而Deque接口则是实现了Queue接口,因此Deque是一个线性的collention,支持在两端插入和移除元素名称 deque 是“double ended queue(双端队列)”的缩写,通常读为“deck”。大多数 Deque 实现对于它们能够包含的元素数没有固定限制,但此接口既支持有容量限制的双端队列,也支持没有固定大小限制的双端队列。

LinkedList的构造方法:

public LinkedList(Collection<? extends E> c) {

this();

addAll(c); //传入一个Collection类型的集合来初始化容器

}

public LinkedList() {

}

我们试着往集合中插入一个元素,看看使用的方法:当我们使用add( E e)时,发现调用的是linkLast方法 ,该方法中的Node是对LinkedList中所有元素操作的数据载体,我们发现在添加的过程中并没有一行代码显示抛出异常,说明在添加元素的时候是链表式的添加,并不会出现像ArrayList中的IndexOutOfBoundsException

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; //如果last 也就是最后一个元素是null的话,呢么添加进来的就是第一个元素

else

l.next = newNode; //否则是下一个元素

size++;

modCount++;

}

 

向指定位置添加元素,该集合并没有初始化长度,

向某个位置添加某个元素的时候,整体的过程如下:

1 先判断集合的长度是否和下标相等,相等的话就直接在集合尾部添加该元素

2 如果不是的话,判断下标在集合中的位置,提高查找效率,因为后边是利用循环查找这个下标的元素,返回这个下标在集合中的Node信息,

3 使用linkBefore方法做一件事情,

 

在添加的时候我们并不需要去像ArrayList一样去不断的复制数组到新的数组,而是直接改变链表内部node节点存储的信息即可快速的向集合中添加元素,因此,在向中间部分添加元素这一过程而言,LinkedList比ArrayList集合要快速的多

并且LinkedList中还提供了很多的便捷的添加方法像:

addFirst( E e):将元素添加到该集合的最前面: add方法内部调用的私有的linkFirst()方法

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

}

addLast( E e ) 调用的是linkLast(E e)方法

移除指定位置的某一个元素remove(int index)方法,

public E remove(int index) {

checkElementIndex(index);//检查下标是否合法

return unlink(node(index));

}

//调用unlike方法

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;//前一个元素如果等于null 呢么下一个元素就是第一个

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

}

话不多说,看图,

通过对双向链表的操作我们还可以实现,单向队列,双向队列 和栈的功能

例如 单向队列:peek()方法,获取但不移除队列的第一个元素

public E peek() {

final Node<E> f = first;

return (f == null) ? null : f.item;

}

getFirst() :返回队列的第一个元素

public E getFirst() {

final Node<E> f = first;

if (f == null)

throw new NoSuchElementException();

return f.item;

}

poll():获取并移除队列的第一个元素

public E poll() {

final Node<E> f = first;

return (f == null) ? null : unlinkFirst(f);

}

像双向队列:offerFirst(E e) 方法 offerLast(E e)方法 peekLast()方法 peekFirst()方法

栈操作:push(E e) pop() 方法,其中的方法还有很多,可以去查一下官方的API文档

总结:

1 linkedList 的底层实现其实是一个双向链表,创建LinkedList对象实例的时候会先加载它的数据节点,初始化的linkedList并没有容量,

2 无论是增删改查还是队列 栈的实现,都是在操纵数据节点之间的链接点,添加的时候需要更新三个节点的数据信息,从数据结构过来看,在查询方面会略逊色于ArrayList,但是在添加或删除元素的时候会比ArrayList效率快很多,因为不需要去copy数组到新数组

3 LinkedList在删除元素的时候所占用的内存会自动缩小,并不需要像ArrayList一样去trimToSize()

4 LinkedList的所有方法也都没有进行同步,因此它也不是线程安全的,因此,我们在考虑线程安全时,需要自己手动的去加一些线程同步机制

5 可以使用LinkedList模拟一些简单的数据结构

使用LinkedList模拟一个队列(FIFO容器)的简单数据结构

将myGet中的.removeLast更改为removeFirst()就模拟了一个栈(先进后出)

package Collection.List.LinkedList;



import java.util.LinkedList;



class MoniDuiLie{

private LinkedList link;



public MoniDuiLie() {

link = new LinkedList();

}

public void myAdd(Object o){

link.addFirst(o);

}

public Object myGet(){

return link.removeLast();

}

public boolean isNull() {

return link.isEmpty();

}

}

public class Duilie {

public static void main(String[] args) {

MoniDuiLie dl = new MoniDuiLie();

dl.myAdd("java01");

dl.myAdd("java02");

dl.myAdd("java03");

dl.myAdd("java04");



while(!dl.isNull())

{

System.out.println(dl.myGet());

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值