LinkedList 底层使用的是双向链表结构
属性
LInkedList的属性很简单,就只有size,头节点和尾节点。Node是LinkedList的一个内部类,结构也比较简单。
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
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;
}
}
常用方法
add()方法
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++;
}
在链表的末尾插入一个新的节点。
remove()方法
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
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;
}
整体来看LinkedList里面的方法都比较好理解,但是其中有一个属性modCount,ArrayList也同样有modCount++操作,为什么呢?
modCount属性
AbstractList抽象方法里面有这么个属性modCount,这是干什么的?看源码
/**
* The number of times this list has been <i>structurally modified</i>.
* Structural modifications are those that change the size of the
* list, or otherwise perturb it in such a fashion that iterations in
* progress may yield incorrect results.
*
* <p>This field is used by the iterator and list iterator implementation
* returned by the {@code iterator} and {@code listIterator} methods.
* If the value of this field changes unexpectedly, the iterator (or list
* iterator) will throw a {@code ConcurrentModificationException} in
* response to the {@code next}, {@code remove}, {@code previous},
* {@code set} or {@code add} operations. This provides
* <i>fail-fast</i> behavior, rather than non-deterministic behavior in
* the face of concurrent modification during iteration.
*
* <p><b>Use of this field by subclasses is optional.</b> If a subclass
* wishes to provide fail-fast iterators (and list iterators), then it
* merely has to increment this field in its {@code add(int, E)} and
* {@code remove(int)} methods (and any other methods that it overrides
* that result in structural modifications to the list). A single call to
* {@code add(int, E)} or {@code remove(int)} must add no more than
* one to this field, or the iterators (and list iterators) will throw
* bogus {@code ConcurrentModificationExceptions}. If an implementation
* does not wish to provide fail-fast iterators, this field may be
* ignored.
*/
protected transient int modCount = 0;
modCount用于记录对象的修改次数,也基本存在于非线程安全的集合类中。注释大致的意思就是modCount用于迭代器中,当多线程环境下,若有个线程在遍历集合的过程中,被另一个线程修改了该集合,就会抛出异常。
测试
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<Integer>();
for (int i = 0; i < 100; i++) {
list.add((int) (Math.random() * 100));
}
new Thread(() -> {
for (int i:list) {
try {
System.out.println(list.get(i));
if(50 == i) {
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
System.out.println("添加元素");
list.add(20,20);
}).start();
}
transient关键字
1.ArrayList中将elementData修饰成transient是为了节省空间
2.LinkedList中将first和last修饰成transient是为了节省空间和重新连接链表。