CopyOnWriteArrayList 源码分析-其它方法

208 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情

indexOf

indexOf 方法主要用于查找元素在数组中的下标位置,如果元素存在就返回元素的下标位置,元素不存在的话返回 -1。并且支持 null 值的搜索,可以正向或者反向的查询。

正向查询源码:

private static int indexOf(Object o, Object[] elements,
                           int index, int fence) {
    if (o == null) {
        for (int i = index; i < fence; i++)
            if (elements[i] == null)
                return i;
    } else {
        for (int i = index; i < fence; i++)
            if (o.equals(elements[i]))
                return i;
    }
    return -1;
}

if (o == null) { } 可以对 null 进行搜索

if (elements[i] == null) return i; 找到第一个 null 值,返回下标索引的位置

for (int i = index; i < fence; i++) if (o.equals(elements[i])) return i;通过 equals 方法来判断元素是否相等,如果相等,返回元素的下标位置

入参o:需要搜索的元素

入参elements:我索的目标数组

入参index:搜索的开始位置

入参fence:搜索的结束位置

总结:

在进行元素是否存在的判断时,也就是contains方法,会使用到indexOf方法进行判断; 在删除元素的方法中,校验元素是否存在,也使用到indexOf方法; indexOf通过一次for循环来查找元素,在调用此方法时,需要注意如果找不到元素时,返回的是 -1,所以在实际使用时,有可能我们会对这个特殊值进行判断。

迭代

在其迭代过程中,即使数组的原值被改变,例如modCount发生改变,也不会抛出 ConcurrentModificationException异常,因为在于数组的每次变动,都会生成新的数组,不会影响老数组,这样的话,迭代过程中,根本就不会发生迭代数组的变动:

    static final class COWIterator<E> implements ListIterator<E> {
        private final Object[] snapshot;
        private int cursor;

        COWIterator(Object[] es, int initialCursor) {
            this.cursor = initialCursor;
            this.snapshot = es;
        }

        public boolean hasNext() {
            return this.cursor < this.snapshot.length;
        }

        public boolean hasPrevious() {
            return this.cursor > 0;
        }

        public E next() {
            if (!this.hasNext()) {
                throw new NoSuchElementException();
            } else {
                return this.snapshot[this.cursor++];
            }
        }

        public E previous() {
            if (!this.hasPrevious()) {
                throw new NoSuchElementException();
            } else {
                return this.snapshot[--this.cursor];
            }
        }
        
        ......
    }

迭代过程中是直接持有原有数组的引用,假设原有数组的值内存地址发生变化,肯定会影响到迭代过程,而 CopyOnWriteArrayList 每次的数据变动,都会产生新的数组,对老数组的值不会产生影响,所以迭代也可以正常进行。

总结

如果需要在线程不安全场景下使用 List 时,可以使用 CopyOnWriteArrayList。