zoukankan      html  css  js  c++  java
  • ArrayList源码

    先介绍几种初始化方法

    // 带初始化容量的初始化
        public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                // 初始话一个object 数组
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) {
                // 初始话一个空数组
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                // 抛出错误
                throw new IllegalArgumentException("Illegal Capacity: "+
                        initialCapacity);
            }
        }
    
        // 默认初始化
        public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
    
        // 使用一个集合初始化
        public ArrayList(Collection<? extends E> c) {
            // 将集合转化成数组
            elementData = c.toArray();
            // size是arraylist的长度,赋予集合的长度
            if ((size = elementData.length) != 0) {
                // 长度不为0, 集合转化为数组后,如果类型不是object的,转为object
                if (elementData.getClass() != Object[].class)
                    elementData = Arrays.copyOf(elementData, size, Object[].class);
            } else {
                // 初始化一个空数组
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }

    重点看下c.toArray方法,假如这个集合是个arraylist类型的,那它的toArray实现如下

        public Object[] toArray() {
            return Arrays.copyOf(elementData, size);
        }

    发现,调用的是Arrays.copyof方法

        public static <T> T[] copyOf(T[] original, int newLength) {
            return (T[]) copyOf(original, newLength, original.getClass());
        }

    继续看

    /**
         *
         * @param original 要复制的数组
         * @param newLength 要复制的长度
         * @param newType 要复制的数组的class类型
         * @param <T>
         * @param <U>
         * @return
         */
        public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
            @SuppressWarnings("unchecked")
            // 这步的作用其实是个优化,假如newType类型是一个object类型,那就直接使用new Object来进行创建数组,加入不是,就用反射的机制创建数组
         // 优化的理由应该是:反射创建数组的性能为比直接创建的性能来的低
    // (Object)newType == (Object)Object[].class 这句话就是判断newType是不是一个object类型 // newType.getComponentType() 其实是获得数组类型,假如说数组是一个String[],那这可以拿到String T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); // 调用本地方法,创建数组 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }

     再介绍ArrayList两个操作

    // 移除所有在c集合里的元素
        public boolean removeAll(Collection<?> c) {
            Objects.requireNonNull(c);
            return batchRemove(c, false);
        }
    
        // 保留所有在c集合里的元素
        public boolean retainAll(Collection<?> c) {
            Objects.requireNonNull(c);
            return batchRemove(c, true);
        }
    
        // 
        private boolean batchRemove(Collection<?> c, boolean complement) {
            final Object[] elementData = this.elementData;
            int r = 0, w = 0;
            boolean modified = false;
            try {
                // 根据complement判断是否保留
                for (; r < size; r++)
                    if (c.contains(elementData[r]) == complement)
                        elementData[w++] = elementData[r];
            } finally {
                // Preserve behavioral compatibility with AbstractCollection,
                // even if c.contains() throws.
                // 假如出现错误,将这个元素后面的所有元素都放到elementData中,不在做去除操作
                if (r != size) {
                    System.arraycopy(elementData, r,
                            elementData, w,
                            size - r);
                    w += size - r;
                }
                // 如果没出现错误
                if (w != size) {
                    // clear to let GC do its work
                    // 将被去除的元素置为null
                    for (int i = w; i < size; i++)
                        elementData[i] = null;
                    // 修改次数
                    modCount += size - w;
                    // 修改当前数组长度
                    size = w;
                    // 表示做过修改
                    modified = true;
                }
            }
            return modified;
        }

     提下java的迭代器,通过迭代器来操作ArrayList

    取得迭代器

    // 返回带指定游标的迭代器ListIterator
        public ListIterator<E> listIterator(int index) {
            if (index < 0 || index > size)
                throw new IndexOutOfBoundsException("Index: "+index);
            return new ListItr(index);
        }
    
        // 返回游标默认为0的迭代器ListIterator
        public ListIterator<E> listIterator() {
            return new ListItr(0);
        }
    
        // 返回默认的迭代器Iterator
        public Iterator<E> iterator() {
            return new Itr();
        }

    再看下迭代器的实现

    Iterator:

        private class Itr implements Iterator<E> {
            int cursor;       // 角标,下个元素的位置
            int lastRet = -1; // 上次操作的元素位置
            int expectedModCount = modCount; //用户操作ArrayList,会改变modCount
    
            public boolean hasNext() {
                return cursor != size; // 角标不为ArrayList长度,则表示有下一个
            }
    
            @SuppressWarnings("unchecked")
            public E next() {
                checkForComodification(); // 检查用户是否在操作ArrayList,如果操作不在迭代
                int i = cursor;
                if (i >= size)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i + 1; // 角标位置+1
                return (E) elementData[lastRet = i]; // 返回当前元素
            }
    
            public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification(); // 检查用户是否在操作ArrayList,如果操作不在迭代
    
                try {
                    ArrayList.this.remove(lastRet); // ArrayList移除这个元素
                    cursor = lastRet;
                    lastRet = -1;
                    expectedModCount = modCount; // 重新赋予新的修改次数
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
    
            // 从当前角标的位置,到结束,consumer为函数编程接口,传各个元素进去执行自定义函数,若在操作过程中,ArrayList发送了修改,则退出迭代,并抛出错误
            @Override
            @SuppressWarnings("unchecked")
            public void forEachRemaining(Consumer<? super E> consumer) {
                Objects.requireNonNull(consumer);
                final int size = ArrayList.this.size;
                int i = cursor;
                if (i >= size) {
                    return;
                }
                final Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length) {
                    throw new ConcurrentModificationException();
                }
                while (i != size && modCount == expectedModCount) {
                    consumer.accept((E) elementData[i++]);
                }
                // update once at end of iteration to reduce heap write traffic
                cursor = i;
                lastRet = i - 1;
                checkForComodification();
            }
    
            // 检查当前的ArrayList是否被修改
            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
        }

    listItr

        private class ListItr extends Itr implements ListIterator<E> {
            // 角标设为index
            ListItr(int index) {
                super();
                cursor = index;
            }
    
            // 判断前面是否有元素
            public boolean hasPrevious() {
                return cursor != 0;
            }
    
            // 返回当前角标,就是下个元素的位置
            public int nextIndex() {
                return cursor;
            }
    
            // 返回当前元素的位置
            public int previousIndex() {
                return cursor - 1;
            }
    
            // 返回当前元素,并将角标改为当前元素的位置
            @SuppressWarnings("unchecked")
            public E previous() {
                checkForComodification();
                int i = cursor - 1;
                if (i < 0)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i;
                return (E) elementData[lastRet = i];
            }
    
            // 设置当前元素的值
            public void set(E e) {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();
    
                try {
                    ArrayList.this.set(lastRet, e);
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
    
            // 将值添加到当前元素之后
            public void add(E e) {
                checkForComodification();
    
                try {
                    int i = cursor;
                    ArrayList.this.add(i, e);
                    cursor = i + 1;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
        }

    可以看出迭代器在遍历数组时,同时可以增加删除,角标都会随之发生变化。

    而如果用for循环遍历ArrayList进行添加删除操作,如果不对当前位置进行一些控制,将发生一些明显的错误。在多线程的情况,操作ArrayList,你将无法知晓其它线程是否有进行添加删除操作,两方同时操作必将发生错误。

    我们可以看看下面的add操作,它只是做了添加一个元素,并将size+1,而迭代器在添加的时候会进行判断modcount是否发生改变,并将角标自动+1。保证了操作的正确性。

        // 添加 元素
        public boolean add(E e) {
            // 调整容量
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            // 赋值,并将szie+1
            elementData[size++] = e;
            return true;
        }
    
        private void ensureCapacityInternal(int minCapacity) {
            // 记得前面默认初始化ArrayList的时候,会将elementData赋值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                // 这时候判断当前的size和DEFAULT_CAPACITY,第一次添加,size为0,所以容量将被初始化为常量10
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    
            ensureExplicitCapacity(minCapacity);
        }
    
        private void ensureExplicitCapacity(int minCapacity) {
            // 修改次数+1,如果迭代器这时候再操作元素,将抛出异常,并中断迭代
            modCount++;
            // 如果minCapacity的容量大于数组中元素的长度
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
    
        private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            //newCapacity为元素长度的1.5倍
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            // minCapacity is usually close to size, so this is a win:
            //扩充元素
            elementData = Arrays.copyOf(elementData, newCapacity);
        }

     

    ArrayList中还有个可分割的迭代器

    //可分割迭代器
        static final class ArrayListSpliterator<E> implements Spliterator<E> {
            //用于存放ArrayList对象
            private final ArrayList<E> list;
            //起始位置(包含),advance/split操作时会修改
            private int index;
            //结束位置(不包含),-1 表示到最后一个元素
            private int fence;
            //用于存放list的modCount
            private int expectedModCount;
    
            ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
                                 int expectedModCount) {
                this.list = list;
                this.index = origin;
                this.fence = fence;
                this.expectedModCount = expectedModCount;
            }
            //获取结束位置(存在意义:首次初始化石需对fence和expectedModCount进行赋值)
            private int getFence() {
                int hi;
                ArrayList<E> lst;
                //fence<0时(第一次初始化时,fence才会小于0):
                if ((hi = fence) < 0) {
                    //list 为 null时,fence=0
                    if ((lst = list) == null)
                        hi = fence = 0;
                    else {
                        //否则,fence = list的长度。
                        expectedModCount = lst.modCount;
                        hi = fence = lst.size;
                    }
                }
                return hi;
            }
            //分割list,返回一个新分割出的spliterator实例
            // 这里要注意,index已被赋值为mid,起始位置已发生改变
            public ArrayListSpliterator<E> trySplit() {
                //hi为当前的结束位置
                //lo 为起始位置
                //计算中间的位置
                int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
                //当lo>=mid,表示不能在分割,返回null
                //当lo<mid时,可分割,切割(lo,mid)出去,同时更新index=mid
                return (lo >= mid) ? null :
                        new ArrayListSpliterator<E>(list, lo, index = mid,                                         expectedModCount);
            }
            //返回true 时,只表示可能还有元素未处理
            //返回false 时,没有剩余元素处理了。。。
            // 注意index+1,角标向前移动了以为,下次再调用这个方法就是处理下个元素
            public boolean tryAdvance(Consumer<? super E> action) {
                if (action == null)
                    throw new NullPointerException();
                //hi为当前的结束位置
                //i 为起始位置
                int hi = getFence(), i = index;
                //还有剩余元素未处理时
                if (i < hi) {
                    //处理i位置,index+1
                    index = i + 1;
                    @SuppressWarnings("unchecked") E e = (E)list.elementData[i];
                    action.accept(e);
                    //遍历时,结构发生变更,抛错
                    if (list.modCount != expectedModCount)
                        throw new ConcurrentModificationException();
                    return true;
                }
                return false;
            }
            //顺序遍历处理所有剩下的元素
            //在这个方法里,角标index不发生变化,并处理index到fence里的元素
            public void forEachRemaining(Consumer<? super E> action) {
                int i, hi, mc; // hoist accesses and checks from loop
                ArrayList<E> lst; Object[] a;
                if (action == null)
                    throw new NullPointerException();
                if ((lst = list) != null && (a = lst.elementData) != null) {
                    //当fence<0时,表示fence和expectedModCount未初始化
                    if ((hi = fence) < 0) { /// 注意hi在这里被赋值
                        mc = lst.modCount;
                        hi = lst.size;
                    }
                    else
                        mc = expectedModCount;
                    if ((i = index) >= 0 && (index = hi) <= a.length) {
                        for (; i < hi; ++i) {
                            @SuppressWarnings("unchecked") E e = (E) a[i];
                            //调用action.accept处理元素
                            action.accept(e);
                        }
                        //遍历时发生结构变更时抛出异常
                        if (lst.modCount == mc)
                            return;
                    }
                }
                throw new ConcurrentModificationException();
            }
    
            // 返回剩下元素长度
            public long estimateSize() {
                return (long) (getFence() - index);
            }
    
            public int characteristics() {
                //打上特征值:、可以返回size
                return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
            }
        }

     使用下这个ArrayList的可分割迭代器

    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
            List<String>  arrs = new ArrayList<>();
            arrs.add("a");
            arrs.add("b");
            arrs.add("c");
            arrs.add("d");
            arrs.add("e");
            arrs.add("f");
            arrs.add("h");
            arrs.add("i");
            arrs.add("j");
    
            Spliterator<String> a =  arrs.spliterator();
            //运行到这里,结果:a:0-9(index-fence)
    
            Spliterator<String> b = a.trySplit();
            //运行到这里,结果:a:4-9 b:0-4
    
            Spliterator<String> c = a.trySplit();
            //运行到这里,结果:a:6-9 b:0-4 c:4-6
        }

    注意,这个分割都是从index到fence,fence一般为迭代器里最大操作位置,index为当前操作的位置,如果操作了第一个元素,比如使用了tryAdvance。那index+1,则分割的时候,也是index到(index+fence)/2;分割出去。

    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
            List<String>  arrs = new ArrayList<>();
            arrs.add("a");
            arrs.add("b");
            arrs.add("c");
            arrs.add("d");
            arrs.add("e");
            arrs.add("f");
            arrs.add("h");
            arrs.add("i");
            arrs.add("j");
    
            Spliterator<String> a =  arrs.spliterator();
            //运行到这里,结果:a:0-9(index-fence)
    
            Consumer<String> t = (inputStr) -> {System.out.println(inputStr.equals("a") ? "的确为a":"不是a啊");};
            a.tryAdvance(t);
            //运行到这里,输出:的确为a
    
            Spliterator<String> b = a.trySplit();
            //运行到这里,结果:a:5-9 b:1-5
    
            Spliterator<String> c = a.trySplit();
            //运行到这里,结果:a:7-9 b:1-5 c:5-7
        }
  • 相关阅读:
    NOI AC#62 color(树上操作)
    fenbi
    bert 压缩优化方向的论文
    bert 编程入门| bert 瘦身技巧
    行政法+刑法+民法
    Bert原理 | Bert油管视频学习法
    vscode的使用以及快捷键总结
    NG课程笔记学习记录
    古典文学+古曲+四大文明古国
    中国地理+地球上的水和大气
  • 原文地址:https://www.cnblogs.com/dj3839/p/8261040.html
Copyright © 2011-2022 走看看