1.简介
源码基于android 23.
- 继承于AbstractSequentialList
,实现了List , Deque , Queue , Cloneable, Serializable接口 - 基于双向循环链表
- 支持null
- 在有类似队列操作时很有用处,也可使用在你的list中有一个或者0个元素时但是你还想list拥有扩展更多元素的能力。
- 在没有队列操作时使用ArrayList是比较好的选择
/**
* LinkedList is an implementation of {@link List}, backed by a doubly-linked list.
* All optional operations including adding, removing, and replacing elements are supported.
*
* All elements are permitted, including null.
*
*
This class is primarily useful if you need queue-like behavior. It may also be useful
* as a list if you expect your lists to contain zero or one element, but still require the
* ability to scale to slightly larger numbers of elements. In general, though, you should
* probably use {@link ArrayList} if you don't need the queue-like behavior.
*
* @since 1.2
*/
2.成员变量
transient int size = 0;
transient Link voidLink;
private static final class Link {
ET data;
Link previous, next;
Link(ET o, Link p, Link n) {
data = o;
previous = p;
next = n;
}
}
3.构造方法
voidLink作为链接指针,最后元素的next指向voidLink的previous,
voidLink的next指向第一个元素的previous
public LinkedList() {
voidLink = new Link(null, null, null);
voidLink.previous = voidLink;
voidLink.next = voidLink;
}
public LinkedList(Collection extends E> collection) {
this();
addAll(collection);
}
4.方法
1.add
public void addFirst(E object) {
addFirstImpl(object);
}
private boolean addFirstImpl(E object) {
Link oldFirst = voidLink.next;
Link newLink = new Link(object, voidLink, oldFirst);
voidLink.next = newLink; //voidLink的next指向新添加元素
oldFirst.previous = newLink;//以前的第一个元素的previous指向新添加元素
size++;
modCount++;
return true;
}
//addLast同理
private boolean addLastImpl(E object) {
Link oldLast = voidLink.previous;
Link newLink = new Link(object, oldLast, voidLink);
voidLink.previous = newLink;//voidLink的previous指向新添加元素
oldLast.next = newLink;//以前最后元素的next指向新添加元素
size++;
modCount++;
return true;
}
//指定位置添加元素,采用简单的二分法则。找到需要插入位置的元素link
@Override
public void add(int location, E object) {
if (location >= 0 && location <= size) {
Link link = voidLink;
//从前到后遍历
if (location < (size / 2)) {
for (int i = 0; i <= location; i++) {
link = link.next;
}
} else {
//从后到前遍历
for (int i = size; i > location; i--) {
link = link.previous;
}
}
//找到link的前一个元素
Link previous = link.previous;
//生成新元素
Link newLink = new Link(object, previous, link);
//link的前一个元素的next指向新添加元素
previous.next = newLink;
//link的previous的指向新添加元素
link.previous = newLink;
size++;
modCount++;
} else {
throw new IndexOutOfBoundsException();
}
}
2.remove
//删除指定位置元素
public E remove(int location) {
if (location >= 0 && location < size) {
Link link = voidLink;
if (location < (size / 2)) {
for (int i = 0; i <= location; i++) {
link = link.next;
}
} else {
for (int i = size; i > location; i--) {
link = link.previous;
}
}
//二分找出需要删除的元素link。找到link的前一个元素和后一个元素
Link previous = link.previous;
Link next = link.next;
//将link的前元素的next指向link的后一个元素
previous.next = next;
//将link的后一个元素的previous指向link的前一个元素
next.previous = previous;
size--;
modCount++;
return link.data;
}
throw new IndexOutOfBoundsException();
}
//删除指定元素
@Override
public boolean remove(Object object) {
return removeFirstOccurrenceImpl(object);
}
private boolean removeFirstOccurrenceImpl(Object o) {
Iterator iter = new LinkIterator(this, 0);
return removeOneOccurrence(o, iter);
}
private boolean removeOneOccurrence(Object o, Iterator iter) {
while (iter.hasNext()) {
E element = iter.next();
//可以操作null。
if (o == null ? element == null : o.equals(element)) {
iter.remove();
return true;
}
}
return false;
}
//删除所有元素,将voidLink的指针指向自己。
@Override
public void clear() {
if (size > 0) {
size = 0;
voidLink.next = voidLink;
voidLink.previous = voidLink;
modCount++;
}
}
3.set
public E set(int location, E object) {
if (location >= 0 && location < size) {
Link link = voidLink;
if (location < (size / 2)) {
for (int i = 0; i <= location; i++) {
link = link.next;
}
} else {
for (int i = size; i > location; i--) {
link = link.previous;
}
}
E result = link.data;
link.data = object;
return result;
}
throw new IndexOutOfBoundsException();
}
4.get
@Override
public E get(int location) {
if (location >= 0 && location < size) {
Link link = voidLink;
if (location < (size / 2)) {
for (int i = 0; i <= location; i++) {
link = link.next;
}
} else {
for (int i = size; i > location; i--) {
link = link.previous;
}
}
return link.data;
}
throw new IndexOutOfBoundsException();
}
@Override
public boolean contains(Object object) {
Link link = voidLink.next;
if (object != null) {
while (link != voidLink) {
if (object.equals(link.data)) {
return true;
}
link = link.next;
}
} else {
while (link != voidLink) {
if (link.data == null) {
return true;
}
link = link.next;
}
}
return false;
}
5.实现Deque接口方法
//返回第一个元素
public E peek() {
return peekFirstImpl();
}
private E peekFirstImpl() {
Link first = voidLink.next;
return first == voidLink ? null : first.data;
}
//添加一个元素到最后
public boolean offer(E o) {
return addLastImpl(o);
}
//移除第一个元素。
public E poll() {
return size == 0 ? null : removeFirst();
}
public E pop() {
return removeFirstImpl();
}
public void push(E e) {
addFirstImpl(e);
}
//正向iterator
@Override
public ListIterator listIterator(int location) {
return new LinkIterator(this, location);
}
//逆向iterator
public Iterator descendingIterator() {
return new ReverseLinkIterator(this);
}
6.序列化,transient的作用还是在于自己手动序列化,不去保存指针,只保存数据,节约空间。在恢复数据时在将链表结构恢复。
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
stream.writeInt(size);
Iterator it = iterator();
while (it.hasNext()) {
stream.writeObject(it.next());
}
}
@SuppressWarnings("unchecked")
private void readObject(ObjectInputStream stream) throws IOException,
ClassNotFoundException {
stream.defaultReadObject();
size = stream.readInt();
voidLink = new Link(null, null, null);
Link link = voidLink;
for (int i = size; --i >= 0;) {
Link nextLink = new Link((E) stream.readObject(), link, null);
link.next = nextLink;
link = nextLink;
}
link.next = voidLink;
voidLink.previous = link;
}
5.ArrayList和LinkedList的比较
- 普通结论:ArrayList基于数组,查询快,增删慢。LinkedList基于链表,查询慢,增删快。
- get和set,ArrayList较快,LinkedList要二分然后for循环查找到指定元素。
- 在remove和add上。LinkedList如果不是在首位位置操作,也需要先查询到指定的元素才能操作(快操作,慢寻址)。ArrayList在这两个操作上时间主要浪费在copy数组上(慢操作,快寻址)。但是ArrayList中remove(index)中
System.arraycopy(a, index + 1, a, index, --s - index);如果删除最后一个元素copy数组不浪费时间,这个时候性能超过LinkedList。add(index)类似。 - index,contains效率差不多
- 迭代效率,建议使用foreach
Trinea分析ArrayList和LinkedList的几种循环遍历方式及性能对比分析