我的原则:先会用再说,内部慢慢来。
学以致用,根据场景学源码
一、架构
1.1 常见子类 UML
1.2 简述
- AbstractCollection 抽象类实现 Collection 接口,实现部分通用方法
- List 接口实现 Collection 接口,增加了链表需要的若干方法。
- AbstractList 继承了 AbstractCollection 抽象类 ,实现了 List 接口,实现了List接口的若干个方法,目的是既拿到AbstractCollection的内部实现,又可以实现 List 接口内部的若干方法。
- List 的子类若实现了RandomAccess 接口,那么内部就是数组 array 结构,若继承了 AbstractSequentialList 抽象类,那么内部就是链表List结构
二、AbstractList 抽象类
- AbstractList 抽象类内部并未定义新的抽象方法等待子类去实现,定义成Abstract类的目的是不用重写父类的全部方法。
2.1 AbstractList 抽象类实现 List 接口的几个方法
实现 List 接口的几个方法 | 备注 |
---|---|
indexOf(Object o) | |
lastIndexOf(Object o) | |
clear() | |
addAll(int index, Collection<? extends E> c) | |
iterator() | return new Itr(); |
listIterator() | return listIterator(0); |
listIterator(final int index) | return new ListItr(index); |
subList(int fromIndex, int toIndex) | return (this instanceof RandomAccess ? new RandomAccessSubList<>(this, fromIndex, toIndex) : new SubList<>(this, fromIndex, toIndex)); |
equals(Object o) | |
hashCode() |
2.2 私有内部类 Itr
2.2.1 UML图
2.2.2 代码
private class Itr implements Iterator<E> {
// 游标
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
// 设置一个flag,如果外面对该 Collection 有任何写操作,都会导致 modCount 的变化。
int expectedModCount = modCount;
// 是否还有后继Node
public boolean hasNext() {
return cursor != size();
}
// 得到后继节点
public E next() {
// 判断该 Collection 是否有任何写操作
checkForComodification();
try {
int i = cursor;
E next = get(i);
// 游标的前一坐标
lastRet = i;
// 游标往后移动
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
// Collection 允许 iterator 边进行遍历边删除
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
// 删除
AbstractList.this.remove(lastRet);
// 正常来说 lastRet = cursor - 1
if (lastRet < cursor)
cursor--;
// 重置
lastRet = -1;
// 内部remove 保持正常状态
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
// 判断该 Collection 是否有任何写操作,如果有,抛出 ConcurrentModificationException
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
2.2.3 checkForComodification方法
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
- 该方法用于检测 Iterator 遍历过程中,外部是否对该Collection进行了改动,若有那么抛出 ConcurrentModificationException 异常。
2.3 私有内部类 ListItr
- java.util.AbstractList.ListItr 继承另一个私有内部类 Itr .从而实现了双向遍历。
2.3.1 ListItr私有内部类 UML图
2.3.2 代码
private class ListItr extends Itr implements ListIterator<E> {
// 设置游标初始位置
ListItr(int index) {
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
// 往前走,找到前一个元素,注意父类有个对应的 next 方法
public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
// 往后走的游标
public int nextIndex() {
return cursor;
}
// 往前走的游标
public int previousIndex() {
return cursor-1;
}
// lastRet ,重新设置当前位置的元素
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
// 调取 AbstractList 实现类的 add 方法。(实例方法)
AbstractList.this.add(i, e);
// lastRet 处理的位置重新来
lastRet = -1;
cursor = i + 1;
// 调用 Iterator 的add 方法, 本身并不会造成 ConcurrentModificationException
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
- 看下 AbstractList.this.set(lastRet, e) ;
- 看下 AbstractList.this.add(i, e); 方法,
ListItr 内部类调用了 AbstractList 子类实例的 set方法与 add 方法。
2.4 包内 default 类 SubList
- 该类可用于部分处理 Collection 内元素,由于 List 链表结构是有序的,所以可以根据下标进行截取。
- 实际上,该类还是主要直接操纵了宿主List,复写了AbstractList抽象类的一些方法,加入了检查与offse处理。
2.4.1 UML 图
2.4.1 代码
class SubList<E> extends AbstractList<E> {
private final AbstractList<E> l;
private final int offset;
private int size;
// 注意一下,这里其实没有截取出一个新的 list ,而是同样操作老的list,其实是个子集
SubList(AbstractList<E> list, int fromIndex, int toIndex) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > list.size())
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
l = list;
// 跳过 N 个下标
offset = fromIndex;
// 长度相应变小
size = toIndex - fromIndex;
this.modCount = l.modCount;
}
// 先检查,后续垫块石头设置 Element
public E set(int index, E element) {
rangeCheck(index);
checkForComodification();
return l.set(index+offset, element);
}
// 先检查,后续垫块石头获取 Element
public E get(int index) {
rangeCheck(index);
checkForComodification();
return l.get(index+offset);
}
public int size() {
checkForComodification();
return size; // 该 size 已经是被削减过的
}
public void add(int index, E element) {
rangeCheckForAdd(index);
checkForComodification();
l.add(index+offset, element);
this.modCount = l.modCount;
size++;
}
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = l.remove(index+offset); // 调用父list的 remove
this.modCount = l.modCount;
size--; //实例变量 size--
return result;
}
// 删除一定范围内的数据,同理调用父list的 remove
protected void removeRange(int fromIndex, int toIndex) {
checkForComodification();
l.removeRange(fromIndex+offset, toIndex+offset);
this.modCount = l.modCount;
size -= (toIndex-fromIndex);
}
// 塞入一个 Collection
public boolean addAll(Collection<? extends E> c) {
// 传入 size ,也就意味着新插入到最后
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
int cSize = c.size();
if (cSize==0)
return false;
checkForComodification();
l.addAll(offset+index, c);
this.modCount = l.modCount;
size += cSize;
return true;
}
public Iterator<E> iterator() {
return listIterator();
}
// 重写父类的 listIterator 方法,做进一步处理
public ListIterator<E> listIterator(final int index) {
checkForComodification();
rangeCheckForAdd(index);
return new ListIterator<E>() {
private final ListIterator<E> i = l.listIterator(index+offset);
public boolean hasNext() {
return nextIndex() < size;
}
public E next() {
if (hasNext())
return i.next();
else
throw new NoSuchElementException();
}
public boolean hasPrevious() {
return previousIndex() >= 0;
}
public E previous() {
if (hasPrevious())
return i.previous();
else
throw new NoSuchElementException();
}
public int nextIndex() {
return i.nextIndex() - offset;
}
public int previousIndex() {
return i.previousIndex() - offset;
}
public void remove() {
i.remove();
SubList.this.modCount = l.modCount;
size--;
}
public void set(E e) {
i.set(e);
}
public void add(E e) {
i.add(e);
SubList.this.modCount = l.modCount;
size++;
}
};
}
public List<E> subList(int fromIndex, int toIndex) {
return new SubList<>(this, fromIndex, toIndex);
}
// 判断下标是否超出限制
private void rangeCheck(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 判断下标是否超出限制 forAdd
private void rangeCheckForAdd(int index) {
// 允许 index == size的情况,也就是插入一个新的,然后add操作会自动把size+1的
if (index < 0 || index > size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 输出打印信息
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
// 判断是否有外部干扰
private void checkForComodification() {
if (this.modCount != l.modCount)
throw new ConcurrentModificationException();
}
}
2.5 包内 default 类 RandomAccessSubList
- RandomAccess 意思是随意访问
- 该类除了实现接口 RandomAccess,对于 SubList 来说,并没有多大的改动。
class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {
RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {
super(list, fromIndex, toIndex);
}
public List<E> subList(int fromIndex, int toIndex) {
return new RandomAccessSubList<>(this, fromIndex, toIndex);
}
}
三、 RandomAccess 接口(为何要空壳?)
3.1 RandomAccess 讲解
- ArrayList 实现了,LinkedList 没实现该接口
public interface RandomAccess {
}
- 该类是干嘛的?
- RandomAccess 意思是随意访问
- 该接口,表示它能快速随机访问存储的元素。意味着内部实现是数组Array的,都会实现这个接口。尽管他啥事都没做。
- RandomAccess 这个标记接口就是标记能够随机访问元素的集合, 简单来说就是底层是数组实现的集合。
- 数组 Array 支持随机访问, 查询速度快, 增删元素慢; 链表List 支持顺序访问, 查询速度慢, 增删元素快。所以对应的 ArrayList 查询速度快,LinkedList 查询速度慢,
3.2 RandomAccess 的常用子类
四、 AbstractSequentialList 类
- Sequential:按次序的,相继的
- 实现此类的内部结构都是链表 list 结构,而并非数组 array
4.1 方法列表
方法名 | 描述 |
---|---|
public E get(int index) | - |
public E set(int index, E element) | - |
public void add(int index, E element) | 在指定index插入 |
public E remove(int index) | - |
public boolean addAll(int index, Collection<? extends E> c) | 在指定index插入另外的Collection |
public Iterator iterator() | |
public abstract ListIterator listIterator(int index) | 在指定index开始返回迭代器 |
- 内部方法均使用迭代器才能进行下标的定位。
五、番外篇
上一章节:【Java Collection】集合类 Collection 剖析(一)
上一章节:【Java Collection】常见 List 子类剖析(三)