LinkedList是使用双向链表实现的List。长处是可以在O(1)复杂度下进行插入、删除操作,弱项是随机访问的复杂度是O(n)。

父类与接口




public class LinkedList<E>

extends AbstractSequentialList<E>

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


LinkedList实现了List和Deque接口,所以可以把LinkedList当做队列或者双向队列使用。

成员变量







//保存双向链表的长度

transient int size = 0;


// 指向头元素的引用

// 永远成立的表达式: (first == null && last == null) ||

// (first.prev == null && first.item != null)

transient Node<E> first;


// 指向尾元素的引用

// 永远成立的表达式【有疑问】: (first == null && last == null) ||

// (last.next == null && last.item != null)

transient Node<E> last;




这里我有一个很大的疑问。就是源码注释的永远成立的表达式,感觉是不对的。因为LinkedList是允许添加null的元素的,所以可能出现(first.prev == null && first.item == null)的情况。

这个时候我心里激动了一下,我擦,我是不是发现了jdk的一个小bug,看看jdk最新代码什么情况,唉,可惜已经被人修复了。。。http://hg.openjdk.java.net/jdk9/dev/jdk/rev/cabf2d0876ef

构造函数



public LinkedList() {

}


//用c集合的元素新建一个LinkedList

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

this();

addAll(c);

}


节点类








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;

}

}




这是链表节点类,因为是双向链表,所以有一个next一个prev引用。

内部用插入/删除方法(链表操作方法)







//添加头部元素

private void linkFirst(E e) {

final Node<E> f = first;

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

first = newNode;


//原来first==null,说明当前链表为空链表,则last也指向新加入的头部元素

if (f == null)

last = newNode;

else

f.prev = newNode;

size++;

modCount++;

}


//追加尾部元素

void linkLast(E e) {

final Node<E> l = last;

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

last = newNode;


//原来的last==null,说明当前链表为空链表,则first也指向新加入的尾部元素

if (l == null)

first = newNode;

else

l.next = newNode;

size++;

modCount++;

}


//在某检点前插入元素,因为是内部使用,所以保证了succ!=null,并且保证succ是当前链表上的节点

void linkBefore(E e, Node<E> succ) {

final Node<E> pred = succ.prev;

final Node<E> newNode = new Node<>(pred, e, succ);

succ.prev = newNode;


//指定节点的前缀==null,说明指定的节点为first,则更新first

if (pred == null)

first = newNode;

//否则,指定节点的前驱的后缀为插入的节点

else

pred.next = newNode;

size++;

modCount++;

}


//删除第一个节点,删除节点需要把节点的前驱,元素,后缀都设置为null,帮助GC

private E unlinkFirst(Node<E> f) {

// assert f == first && f != null;

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;

}


//删除最后一个节点,删除节点需要把节点的前驱,元素,后缀都设置为null,帮助GC

private E unlinkLast(Node<E> l) {

// assert l == last && l != null;

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;

}


//删除某个节点

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;

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

这些内部方法如果传入的是Node,则需要保证两点:

  • 不为空

  • 是当前LinkedList上的节点

从首尾部获取/添加/删除元素


都是实现Deque接口的方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41




//获取第一个元素,如果列表为空,报错

public E getFirst() {

final Node<E> f = first;

if (f == null)

throw new NoSuchElementException();

return f.item;

}


//获取最后一个元素,如果列表为空,报错

public E getLast() {

final Node<E> l = last;

if (l == null)

throw new NoSuchElementException();

return l.item;

}


//删除第一个元素

public E removeFirst() {

final Node<E> f = first;

if (f == null)

throw new NoSuchElementException();

return unlinkFirst(f);

}


//删除最后一个元素

public E removeLast() {

final Node<E> l = last;

if (l == null)

throw new NoSuchElementException();

return unlinkLast(l);

}


//在首部添加元素

public void addFirst(E e) {

linkFirst(e);

}


//在尾部追加元素

public void addLast(E e) {

linkLast(e);

}




使用上面包装好的链表操作函数,这些函数的实现变得很简单。

这几个方法如果在获取、删除时发现列表是空的会报出NoSuchElementException。

查找与搜索


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35




//判断列表中是否存在元素

public boolean contains(Object o) {

return indexOf(o) != -1;

}


//获取长度

public int size() {

return size;

}


//追加元素,和addLast是等价的

public boolean add(E e) {

linkLast(e);

return true;

}


//删除链表中第一次出现的指定对象,通过遍历列表实现

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;

}




批量操作


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59




//添加另外一个集合的元素,如果在添加过程中,外部集合的内容被修改了,行为是不确定的

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) //如果外部集合为空,直接返回false

return false;


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

}


//清空所有元素

public void clear() {

// 把元素都设置为null,帮助GC

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

}




基于位置的操作


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79




//返回特定位置上的元素

public E get(int index) {

checkElementIndex(index);

return node(index).item;

}


//替换指定位置上的元素

public E set(int index, E element) {

checkElementIndex(index);

Node<E> x = node(index);

E oldVal = x.item;

x.item = element;

return oldVal;

}


//在指定位置插入元素

public void add(int index, E element) {

checkPositionIndex(index);


if (index == size)

linkLast(element);

else

linkBefore(element, node(index));

}


//删除指定位置上的元素

public E remove(int index) {

checkElementIndex(index);

return unlink(node(index));

}


//判断index是否合法

private boolean isElementIndex(int index) {

return index >= 0 && index < size;

}


//判断index是否可以用来add或者用来迭代。多了一个index==size的合法位置,因为可以在size上添加最后一个元素

private boolean isPositionIndex(int index) {

return index >= 0 && index <= size;

}


//拼接位置错误信息

private String outOfBoundsMsg(int index) {

return "Index: "+index+", Size: "+size;

}


//检查index是否合法,不合法就报错

private void checkElementIndex(int index) {

if (!isElementIndex(index))

throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

}


//判断index是否可以用来add或者用来迭代,不合法就报错

private void checkPositionIndex(int index) {

if (!isPositionIndex(index))

throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

}


//返回指定位置上的元素

Node<E> node(int index) {

//必须在外部保证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;

}

}




搜索操作


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37




//从前往后搜索指定元素位置,如果找不到,返回-1

public int indexOf(Object o) {

int index = 0;

if (o == null) {

for (Node<E> x = first; x != null; x = x.next) {

if (x.item == null)

return index;

index++;

}

} else {

for (Node<E> x = first; x != null; x = x.next) {

if (o.equals(x.item))

return index;

index++;

}

}

return -1;

}


//从后往前搜索指定元素位置,如果找不到,返回-1

public int lastIndexOf(Object o) {

int index = size;

if (o == null) {

for (Node<E> x = last; x != null; x = x.prev) {

index--;

if (x.item == null)

return index;

}

} else {

for (Node<E> x = last; x != null; x = x.prev) {

index--;

if (o.equals(x.item))

return index;

}

}

return -1;

}




队列操作(Queue接口)


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26




//返回第一个元素,但是不会删除。如果列表为空,返回null

public E peek() {

final Node<E> f = first;

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

}


//返回第一个元素,但是不会删除。如果列表为空,报出NoSuchElementException

public E element() {

return getFirst();

}


//返回第一个元素并删除。如果列表为空返回null

public E poll() {

final Node<E> f = first;

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

}


//返回并删除第一个元素。如果列表为空报NoSuchElementException

public E remove() {

return removeFirst();

}


//追加元素

public boolean offer(E e) {

return add(e);

}




双端队列操作(Deque接口)


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70




//从头部插入元素

public boolean offerFirst(E e) {

addFirst(e);

return true;

}


//从尾部插入元素

public boolean offerLast(E e) {

addLast(e);

return true;

}


//获取第一个元素,如果列表为空返回null

public E peekFirst() {

final Node<E> f = first;

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

}


//获取最后一个元素,如果列表为空返回null

public E peekLast() {

final Node<E> l = last;

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

}


//获取并删除第一个元素,如果列表为空返回null

public E pollFirst() {

final Node<E> f = first;

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

}


//获取并删除最后一个元素,如果列表为空返回null

public E pollLast() {

final Node<E> l = last;

return (l == null) ? null : unlinkLast(l);

}


//栈push操作

public void push(E e) {

addFirst(e);

}


//栈pop操作

public E pop() {

return removeFirst();

}


//删除从前往后第一个出现的相等元素

public boolean removeFirstOccurrence(Object o) {

return remove(o);

}


//删除从后往前第一个出现的相等元素

public boolean removeLastOccurrence(Object o) {

if (o == null) {

for (Node<E> x = last; x != null; x = x.prev) {

if (x.item == null) {

unlink(x);

return true;

}

}

} else {

for (Node<E> x = last; x != null; x = x.prev) {

if (o.equals(x.item)) {

unlink(x);

return true;

}

}

}

return false;

}




迭代器操作


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125




//获取LinkedList的ListIterator

public ListIterator<E> listIterator(int index) {

checkPositionIndex(index);

return new ListItr(index);

}


//是fail-fast的

private class ListItr implements ListIterator<E> {

private Node<E> lastReturned;

private Node<E> next;

private int nextIndex;

private int expectedModCount = modCount;


ListItr(int index) {

// assert isPositionIndex(index);

next = (index == size) ? null : node(index);

nextIndex = index;

}


//判断是否还有元素,不是通过null而是通过size

public boolean hasNext() {

return nextIndex < size;

}


public E next() {

checkForComodification();

if (!hasNext())

throw new NoSuchElementException();


lastReturned = next;

next = next.next;

nextIndex++;

return lastReturned.item;

}


public boolean hasPrevious() {

return nextIndex > 0;

}


public E previous() {

checkForComodification();

if (!hasPrevious())

throw new NoSuchElementException();


lastReturned = next = (next == null) ? last : next.prev;

nextIndex--;

return lastReturned.item;

}


public int nextIndex() {

return nextIndex;

}


public int previousIndex() {

return nextIndex - 1;

}


public void remove() {

checkForComodification();

if (lastReturned == null)

throw new IllegalStateException();


Node<E> lastNext = lastReturned.next;

unlink(lastReturned);

if (next == lastReturned)

next = lastNext;

else

nextIndex--;

lastReturned = null;

expectedModCount++;

}


public void set(E e) {

if (lastReturned == null)

throw new IllegalStateException();

checkForComodification();

lastReturned.item = e;

}


public void add(E e) {

checkForComodification();

lastReturned = null;

if (next == null)

linkLast(e);

else

linkBefore(e, next);

nextIndex++;

expectedModCount++;

}


public void forEachRemaining(Consumer<? super E> action) {

Objects.requireNonNull(action);

while (modCount == expectedModCount && nextIndex < size) {

action.accept(next.item);

lastReturned = next;

next = next.next;

nextIndex++;

}

checkForComodification();

}


final void checkForComodification() {

if (modCount != expectedModCount)

throw new ConcurrentModificationException();

}

}


//获取逆向迭代器

public Iterator<E> descendingIterator() {

return new DescendingIterator();

}


//逆向迭代器是基于正向迭代器的简单包装

private class DescendingIterator implements Iterator<E> {

private final ListItr itr = new ListItr(size());

public boolean hasNext() {

return itr.hasPrevious();

}

public E next() {

return itr.previous();

}

public void remove() {

itr.remove();

}

}




克隆与获取数组


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50




@SuppressWarnings("unchecked")

private LinkedList<E> superClone() {

try {

return (LinkedList<E>) super.clone();

} catch (CloneNotSupportedException e) {

throw new InternalError(e);

}

}


//克隆LinkedList,会克隆每个Node,但是不会克隆每个元素的内容

public Object clone() {

LinkedList<E> clone = superClone();


// 保持处女的状态(原始注释可就是这句哦)

clone.first = clone.last = null;

clone.size = 0;

clone.modCount = 0;


// Initialize clone with our elements

for (Node<E> x = first; x != null; x = x.next)

clone.add(x.item);


return clone;

}


//返回数组

public Object[] toArray() {

Object[] result = new Object[size];

int i = 0;

for (Node<E> x = first; x != null; x = x.next)

result[i++] = x.item;

return result;

}


//返回指定类型的数组

@SuppressWarnings("unchecked")

public <T> T[] toArray(T[] a) {

if (a.length < size)

a = (T[])java.lang.reflect.Array.newInstance(

a.getClass().getComponentType(), size);

int i = 0;

Object[] result = a;

for (Node<E> x = first; x != null; x = x.next)

result[i++] = x.item;


if (a.length > size)

a[size] = null;


return a;

}




序列化/反序列化


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30




private static final long serialVersionUID = 876323262645176354L;


//序列化,写入size,然后是没一个元素,注意LinkedList中size也是transient的

private void writeObject(java.io.ObjectOutputStream s)

throws java.io.IOException {

// Write out any hidden serialization magic

s.defaultWriteObject();


// Write out size

s.writeInt(size);


// Write out all elements in the proper order.

for (Node<E> x = first; x != null; x = x.next)

s.writeObject(x.item);

}


//反序列化

@SuppressWarnings("unchecked")

private void readObject(java.io.ObjectInputStream s)

throws java.io.IOException, ClassNotFoundException {

// Read in any hidden serialization magic

s.defaultReadObject();


// Read in size

int size = s.readInt();


// Read in all elements in the proper order.

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

linkLast((E)s.readObject());

}




Java8中的新方法


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109




/**

* Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>

* and <em>fail-fast</em> {@link Spliterator} over the elements in this

* list.

*

* <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and

* {@link Spliterator#ORDERED}. Overriding implementations should document

* the reporting of additional characteristic values.

*

* @implNote

* The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}

* and implements {@code trySplit} to permit limited parallelism..

*

* @return a {@code Spliterator} over the elements in this list

* @since 1.8

*/

@Override

public Spliterator<E> spliterator() {

return new LLSpliterator<E>(this, -1, 0);

}


/** A customized variant of Spliterators.IteratorSpliterator */

static final class LLSpliterator<E> implements Spliterator<E> {

static final int BATCH_UNIT = 1 << 10; // batch array size increment

static final int MAX_BATCH = 1 << 25; // max batch array size;

final LinkedList<E> list; // null OK unless traversed

Node<E> current; // current node; null until initialized

int est; // size estimate; -1 until first needed

int expectedModCount; // initialized when est set

int batch; // batch size for splits


LLSpliterator(LinkedList<E> list, int est, int expectedModCount) {

this.list = list;

this.est = est;

this.expectedModCount = expectedModCount;

}


final int getEst() {

int s; // force initialization

final LinkedList<E> lst;

if ((s = est) < 0) {

if ((lst = list) == null)

s = est = 0;

else {

expectedModCount = lst.modCount;

current = lst.first;

s = est = lst.size;

}

}

return s;

}


public long estimateSize() { return (long) getEst(); }


public Spliterator<E> trySplit() {

Node<E> p;

int s = getEst();

if (s > 1 && (p = current) != null) {

int n = batch + BATCH_UNIT;

if (n > s)

n = s;

if (n > MAX_BATCH)

n = MAX_BATCH;

Object[] a = new Object[n];

int j = 0;

do { a[j++] = p.item; } while ((p = p.next) != null && j < n);

current = p;

batch = j;

est = s - j;

return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);

}

return null;

}


public void forEachRemaining(Consumer<? super E> action) {

Node<E> p; int n;

if (action == null) throw new NullPointerException();

if ((n = getEst()) > 0 && (p = current) != null) {

current = null;

est = 0;

do {

E e = p.item;

p = p.next;

action.accept(e);

} while (p != null && --n > 0);

}

if (list.modCount != expectedModCount)

throw new ConcurrentModificationException();

}


public boolean tryAdvance(Consumer<? super E> action) {

Node<E> p;

if (action == null) throw new NullPointerException();

if (getEst() > 0 && (p = current) != null) {

--est;

E e = p.item;

current = p.next;

action.accept(e);

if (list.modCount != expectedModCount)

throw new ConcurrentModificationException();

return true;

}

return false;

}


public int characteristics() {

return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;

}

}




总结



  • LinkedList就是普通的双向链表,但是他可以作为列表,队列,双向队列,栈使用,是一个功能很多的集合类

  • LinkedList在实现了几个链表操作函数后,使用这些函数来保证Deque等接口的方法,核心代码不多

  • ❤️获取指定位置上的元素,LinkedList使用了加速技巧:判断位置在前半区间还是后半区间,如果在前半区间,从前往后遍历,如果在后半区间,从后往前遍历

  • LinkedList因为实现了Deque,所以存在大量冗余的方法,具体可以参考:JDK源码阅读-Queue/Deque | 木杉的博客

  • LinkedList实现了Deque,可以获取逆向迭代器,而逆向迭代器是正向迭代器的简单包装

参考资料