java的继承关系linkedlist_Java集合--LinkedList

概要

LinkedList 是一个双向链表,实现了 List 和 Deque 接口。它允许元素为空,非线程安全。

Deque 是一个双端队列,允许2端分别添加和删除元素。JDK中的说明是这样的

A linear collection that supports element insertion and removal at both ends. The name deque is short for "double ended queue" and is usually pronounced "deck". Most Deque implementations place no fixed limits on the number of elements they may contain, but this interface supports capacity-restricted deques as well as those with no fixed size limit.

继承关系

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

LinkedList 区别于 ArrayList,它是继承自 AbstractSequentialList,并且没有实现 RandomAccess 接口。

如果集合类是 RandomAccess 的实现,尽量用for(int i = 0; i < size; i++) 来遍历而不要用Iterator迭代器来遍历。

反过来,如果List是 Sequence List,则最好用迭代器来进行迭代。后面会看到如果对 LinkedList 使用普通的 for 循环,因为数据结构的原因性能会很差。

AbstractSequentialList 的官方说明如下

This class provides a skeletal implementation of the List interface to minimize the effort required to implement this interface backed by a "sequential access" data store (such as a linked list). For random access data (such as an array), AbstractList should be used in preference to this class.

AbstractSequentialList 提供了一个顺序访问的集合,想要随机访问的话优先使用 AbstractList 的子类。

内部结构

内部类 全局变量

transient int size = 0;

/**

* Pointer to first node.

*/

transient Node first;

/**

* Pointer to last node.

*/

transient Node last;

private static class Node {

E item;

Node next;

Node prev;

Node(Node prev, E element, Node next) {

this.item = element;

this.next = next;

this.prev = prev;

}

}

一个 Node 内部类,包含数据体本身以及一个指向前面节点的指针和一个指向后面节点的指针。

全局的指向头和尾的 first last 指针。

LinkedList 内部是一个双向链表结构。

构造方法

public LinkedList() {

}

public LinkedList(Collection extends E> c) {

this();

addAll(c);

}

public boolean addAll(Collection extends E> c) {

return addAll(size, c);

}

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 pred, succ;

if (index == size) {

succ = null;

pred = last;

} else {

succ = node(index);

pred = succ.prev;

}

for (Object o : a) {

@SuppressWarnings("unchecked") E e = (E) o;

Node newNode = new Node<>(pred, e, null);

if (pred == null)

first = newNode;

else

pred.next = newNode;

pred = newNode;

}

if (succ == null) {

last = pred;

} else {

pred.next = succ;

succ.prev = pred;

}

size += numNew;

modCount++;

return true;

}

提供了2个构造方法,无参的构造方法什么事都不做,接收一个 collection 的构造方法将新的集合放到链表的尾端,将 last 指针指向最后一个节点。

add

public boolean add(E e) {

linkLast(e);

return true;

}

void linkLast(E e) {

final Node l = last;

final Node newNode = new Node<>(l, e, null);

last = newNode;

if (l == null)

first = newNode;

else

l.next = newNode;

size++;

modCount++;

}

add 方法调用的 linkLast 方法,方法很简单 就是新建了一个node节点放到了链表的最后。

LinkedList大多都是链表操作,代码也比较简单,看下就懂了,下面稍微列出几个方法。

// add first

public void addFirst(E e) {

linkFirst(e);

}

void linkLast(E e) {

final Node l = last;

final Node newNode = new Node<>(l, e, null);

last = newNode;

if (l == null)

first = newNode;

else

l.next = newNode;

size++;

modCount++;

}

// add last

public void addLast(E e) {

linkLast(e);

}

private void linkFirst(E e) {

final Node f = first;

final Node newNode = new Node<>(null, e, f);

first = newNode;

if (f == null)

last = newNode;

else

f.prev = newNode;

size++;

modCount++;

}

// remove

public E removeFirst() {

final Node f = first;

if (f == null)

throw new NoSuchElementException();

return unlinkFirst(f);

}

private E unlinkFirst(Node f) {

final E element = f.item;

final Node 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;

}

遍历

如开头说的 AbstractSequentialList 不要使用随机访问的方式遍历,应该采用迭代器或者foreach(foreach 底层是迭代器)。

因为 LinkedList 是个链表,无法像数组一样直接使用下标的方式取到对应的值。

// 随机访问的方式遍历

int size = list.size();

for (int i=0; i

list.get(i);

}

看一下它的get方法

public E get(int index) {

checkElementIndex(index);

return node(index).item;

}

Node node(int index) {

if (index < (size >> 1)) {

Node x = first;

for (int i = 0; i < index; i++)

x = x.next;

return x;

} else {

Node x = last;

for (int i = size - 1; i > index; i--)

x = x.prev;

return x;

}

}

通过 size >> 1 取到一个相对中间的值,然后比较 index 是在前面一段还是后面一段,再按顺序遍历到指定的位置。多此一举。

总结

LinkedList 的大多数API都是基于一个双向链表的操作,循环遍历的时候采用迭代器或者foreach,避免使用普通的for循环。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值