【Java Collection】List 剖析(二)

我的原则:先会用再说,内部慢慢来。
学以致用,根据场景学源码


一、架构

1.1 常见子类 UML

在这里插入图片描述

1.2 简述
  1. AbstractCollection 抽象类实现 Collection 接口,实现部分通用方法
  2. List 接口实现 Collection 接口,增加了链表需要的若干方法。
  3. AbstractList 继承了 AbstractCollection 抽象类 ,实现了 List 接口,实现了List接口的若干个方法,目的是既拿到AbstractCollection的内部实现,又可以实现 List 接口内部的若干方法。
  4. List 的子类若实现了RandomAccess 接口,那么内部就是数组 array 结构,若继承了 AbstractSequentialList 抽象类,那么内部就是链表List结构

=== 点击查看top目录 ===

二、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图

在这里插入图片描述
=== 点击查看top目录 ===

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 异常。

=== 点击查看top目录 ===

2.3 私有内部类 ListItr
  • java.util.AbstractList.ListItr 继承另一个私有内部类 Itr .从而实现了双向遍历。
2.3.1 ListItr私有内部类 UML图

在这里插入图片描述

=== 点击查看top目录 ===

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 方法。

=== 点击查看top目录 ===

2.4 包内 default 类 SubList
  • 该类可用于部分处理 Collection 内元素,由于 List 链表结构是有序的,所以可以根据下标进行截取。
  • 实际上,该类还是主要直接操纵了宿主List,复写了AbstractList抽象类的一些方法,加入了检查与offse处理。
2.4.1 UML 图

在这里插入图片描述

=== 点击查看top目录 ===

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

=== 点击查看top目录 ===

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

=== 点击查看top目录 ===

三、 RandomAccess 接口(为何要空壳?)

3.1 RandomAccess 讲解
  • ArrayList 实现了,LinkedList 没实现该接口
public interface RandomAccess {
}
  • 该类是干嘛的?
  1. RandomAccess 意思是随意访问
  2. 该接口,表示它能快速随机访问存储的元素。意味着内部实现是数组Array的,都会实现这个接口。尽管他啥事都没做。
  3. RandomAccess 这个标记接口就是标记能够随机访问元素的集合, 简单来说就是底层是数组实现的集合。
  4. 数组 Array 支持随机访问, 查询速度快, 增删元素慢; 链表List 支持顺序访问, 查询速度慢, 增删元素快。所以对应的 ArrayList 查询速度快,LinkedList 查询速度慢,

=== 点击查看top目录 ===

3.2 RandomAccess 的常用子类

在这里插入图片描述
=== 点击查看top目录 ===

四、 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开始返回迭代器
  • 内部方法均使用迭代器才能进行下标的定位。

=== 点击查看top目录 ===


五、番外篇

上一章节:【Java Collection】集合类 Collection 剖析(一)
上一章节:【Java Collection】常见 List 子类剖析(三)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值