8,查找元素
1,查找首个为指定元素所在位置indexOf(Object o)
indexOf(Object o)
方法,查找首个为指定元素的位置。代码如下:
public int indexOf(Object o) {
int index = 0;
if (o == null) { // 如果 o 为 null 的情况
for (Node<E> x = first; x != null; x = x.next) { // 顺序遍历,如果 item 为 null 的节点,进行返回
if (x.item == null)
return index; // 找到
index++;
}
} else { // 如果 o 非 null 的情况
for (Node<E> x = first; x != null; x = x.next) { // 顺序遍历,如果 item 为 o 的节点,进行返回
if (o.equals(x.item))
return index; // 找到
index++;
}
}
return -1; // 未找到
}
contains(Object o)是否包含
方法,就是基于该方法实现
public boolean contains(Object o) {
return indexOf(o) != -1;
}
2,查找最后一个为指定元素所在位置lastIndexOf(Object o)
lastIndexOf(Object o) 方法,查找最后个为指定元素的位置。代码如下:
public int lastIndexOf(Object o) {
int index = size;
if (o == null) { // 如果 o 为 null 的情况
for (Node<E> x = last; x != null; x = x.prev) { // 倒序遍历,如果 item 为 null 的节点,进行返回
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; //未找到
}
3,获得指定位置的元素get(int index)
get(int index)
方法,获得指定位置的元素。代码如下:
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
因为LinkedList实现了Deque 接口,所以有peekFirst(),peekLast()
方法分别获得元素到链表的头尾
4,获取元素链头peekFirst()
peekFirst()获得元素到链表的头,代码如下:
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
4,获取元素链尾peekLast()
peekLast()获得元素到链表的尾,代码如下:
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
因为 LinkedList 实现了 Queue 接口,所以它实现了 getFirst()和#peek()和 #element()方法,分别获得元素到链表的头。代码如下:
5,Queue获取链表头
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
public E element() {
return getFirst();
}
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
9,设置元素方法
1,设置指定位置的元素值set(int index, E element)
set(int index, E element)
方法,设置指定位置的元素。代码如下:
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element; // 修改对应的值
return oldVal; //返回修改签的值
}
10,转换成数组toArray()
toArray()
方法,将 ArrayList 转换成 []
数组。代码如下:
public Object[] toArray() {
Object[] result = new Object[size]; // 创建 Object 数组
int i = 0;
for (Node<E> x = first; x != null; x = x.next) // 顺序遍历节点,设置到 Object 数组中
result[i++] = x.item;
return result;
}
还可以给他转换成的数组泛型toArray(T[] a)
方法,代码如下:
public <T> T[] toArray(T[] a) {
if (a.length < size) //如果传入的数组小于 size 大小,则直接复制一个新数组返回
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0; //顺序遍历链表,复制到 a 中
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;
}
11,求哈希值hashCode()
hashCode()
方法,求 LinkedList 的哈希值。代码如下:
public int hashCode() {
int hashCode = 1;
for (E e : this)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
return hashCode;
}
12, 判断相等equals(Object o)
equals(Object o)
方法,判断是否相等。代码如下:
是通过父类AbstractList实现的,通过迭代器实现遍历对比的
public boolean equals(Object o) {
if (o == this) // 如果是自己,直接返回相等
return true;
if (!(o instanceof List)) // 如果不为 List 类型,直接不相等
return false;
// 创建迭代器,顺序遍历比对
ListIterator<E> e1 = listIterator();
ListIterator<?> e2 = ((List<?>) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}// 如果有迭代器没有遍历完,说明两者长度不等,所以就不相等;否则,就相等了
return !(e1.hasNext() || e2.hasNext());
}
13,清空链表clear()
clear()
方法,清空链表。代码如下:
public void clear() {
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
for (Node<E> x = first; x != null; ) { //顺序遍历链表,设置每个节点前后指向为 null 通过这样的方式,帮助 GC
Node<E> next = x.next; // 获得下一个节点
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null; // 清空 first 和 last 指向
size = 0; // 设置链表大小为 0
modCount++; // 增加数组修改次数
}
14,序列化链表writeObject(java.io.ObjectOutputStream s)
writeObject(java.io.ObjectOutputStream s)
方法,实现 LinkedList 的序列化。代码如下:
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out any hidden serialization magic // 写入非静态属性、非 transient 属性
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);
}
15, 反序列化链表readObject(java.io.ObjectInputStream s)
readObject(java.io.ObjectInputStream s)
方法,反序列化数组。代码如下:
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic // 读取非静态属性、非 transient 属性
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());
}
16,克隆clone()
clone()
方法,克隆 LinkedList 对象。代码如下:
public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state 重置 clone 为初始化状态
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements 遍历遍历,逐个添加到 clone 中
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
17,创建子数组subList(int fromIndex, int toIndex)
subList(int fromIndex, int toIndex)
方法,创建 ArrayList 的子数组。代码如下:不包括后面
public List<E> subList(int fromIndex, int toIndex) { // 根据判断 RandomAccess 接口,判断是否支持随机访问
return (this instanceof RandomAccess ?
new RandomAccessSubList<>(this, fromIndex, toIndex) :
new SubList<>(this, fromIndex, toIndex));
}
18,创建Iterator 迭代器iterator()
iterator()
方法,创建迭代器。代码如下:
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator() {
return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
19,创建 ListIterator 迭代器listIterator(int index)
listIterator(int index)
方法,创建 ListIterator 迭代器。代码如下:
从index开始创建迭代器
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
创建ListIterator迭代器
因为 ListItr 的实现代码比较简单,我们就不逐个来看了
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned; //最后返回的节点
private Node<E> next; //下一个节点
private int nextIndex; //下一个访问元素的位置,从下标 0 开始 主要用于 {@link #nextIndex()} 中,判断是否遍历结束
private int expectedModCount = modCount; //创建迭代器时,数组修改次数。 在迭代过程中,如果数组发生了变化,会抛出 ConcurrentModificationException 异常。
ListItr(int index) { //获得下一个节点
// assert isPositionIndex(index);
next = (index == size) ? null : node(index); // 下一个节点的位置
nextIndex = index;
}
public boolean hasNext() {
return nextIndex < size;
}
public E next() {
checkForComodification(); // 校验是否数组发生了变化
if (!hasNext())
throw new NoSuchElementException(); // 如果已经遍历到结尾,抛出 NoSuchElementException 异常
lastReturned = next; // lastReturned 指向,记录最后访问节点
next = next.next; // next 指向,下一个节点
nextIndex++; // 下一个节点的位置 + 1
return lastReturned.item; // 返回 lastReturned
}
public boolean hasPrevious() {
return nextIndex > 0;
}
public E previous() {
checkForComodification(); // 校验是否数组发生了变化
if (!hasPrevious())
throw new NoSuchElementException(); // 如果已经遍历到结尾,抛出 NoSuchElementException 异常
lastReturned = next = (next == null) ? last : next.prev; // 修改 lastReturned 和 next 的指向。此时,lastReturned 和 next 是相等的。
nextIndex--; // 下一个节点的位置 - 1
return lastReturned.item; // 返回 lastReturned
}
public int nextIndex() {
return nextIndex;
}
public int previousIndex() {
return nextIndex - 1;
}
public void remove() {
checkForComodification(); // 校验是否数组发生了变化
if (lastReturned == null) // 如果 lastReturned 为空,抛出 IllegalStateException 异常,因为无法移除了。
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next; // 获得 lastReturned 的下一个
unlink(lastReturned); // 移除 lastReturned 节点
if (next == lastReturned) // 此处,会分成两种情况
next = lastNext;
else
nextIndex--;
lastReturned = null; // 设置 lastReturned 为空
expectedModCount++; // 增加数组修改次数
}
public void set(E e) {
if (lastReturned == null) // 如果 lastReturned 为空,抛出 IllegalStateException 异常,因为无法修改了。
throw new IllegalStateException();
checkForComodification(); // 校验是否数组发生了变化
lastReturned.item = e;
}
public void add(E e) {
checkForComodification(); // 校验是否数组发生了变化
lastReturned = null; // 设置 lastReturned 为空
if (next == null) // 此处,会分成两种情况
linkLast(e); // 如果 next 已经遍历到尾,则 e 作为新的尾节点,进行插入。算是性能优化
else
linkBefore(e, next); // 插入到 next 的前面
nextIndex++; // nextIndex 加一。
expectedModCount++; // 增加数组修改次数
}
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action); // 遍历剩余链表
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item); // 执行 action 逻辑
lastReturned = next; // lastReturned 指向 next
next = next.next; // next 指向下一个节点
nextIndex++; // nextIndex 加一。
}
checkForComodification(); // 校验是否数组发生了变化
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}