zoukankan      html  css  js  c++  java
  • 集合-ArrayList

    对于调试jdk源码,若是发现无法在调试过程中查看源码中的变量,可以参考这篇文章:https://blog.csdn.net/u010407050/article/details/76690478

    参考:http://www.cnblogs.com/skywang12345/p/3323085.html

    removeIf() 方法 https://blog.csdn.net/qq_27093465/article/details/79154566

    在接口collection里面的一个默认方法,当继承collection后,如果不自己实现这个方法就会采用这个默认的方法。

    java.util.ArrayList.removeIf   ArrayList类重写了这个方法
      @Override
        public boolean removeIf(Predicate<? super E> filter) {
            Objects.requireNonNull(filter);
            // figure out which elements are to be removed
            // any exception thrown from the filter predicate at this stage
            // will leave the collection unmodified
            int removeCount = 0; //记录删除元素的个数
            final BitSet removeSet = new BitSet(size);  //记录被删除的元素的索引 在需要删除的元素那个索引那置为true
            final int expectedModCount = modCount;   //在未做处理前被更改的次数
            final int size = this.size;  //集合包含元素的个数
            for (int i=0; modCount == expectedModCount && i < size; i++) {
                @SuppressWarnings("unchecked")
                final E element = (E) elementData[i];
                if (filter.test(element)) {  //按照过滤器来确定删除哪些元素,以及这些元素的索引
                    removeSet.set(i);
                    removeCount++;
                }
            }
            if (modCount != expectedModCount) { //若不相等则说明在删除的过程中,集合被其他的线程修改了
                throw new ConcurrentModificationException();
            }
            // shift surviving elements left over the spaces left by removed elements
            final boolean anyToRemove = removeCount > 0;
            if (anyToRemove) {//这里才是真正开始集合删除元素
                final int newSize = size - removeCount; //新的集合的大小
                for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) { 将那些标志位false的元素往左移,填补那些需要删除的元素的位置
                    i = removeSet.nextClearBit(i);
                    elementData[j] = elementData[i];
                }
                for (int k=newSize; k < size; k++) { 将新的集合的新长度之后的元素都置为null,便于gc进行垃圾回收
                    elementData[k] = null;  // Let gc do its work
                }
                this.size = newSize;
                if (modCount != expectedModCount) {
                    throw new ConcurrentModificationException();
                }
                modCount++; 
            }
            return anyToRemove;
        }

    参考:http://www.cnblogs.com/skywang12345/p/3308556.html

              http://www.cnblogs.com/zhangyinhua/p/7687377.html

    ArrayList

    //void java.util.ArrayList.trimToSize()
        /**
         * Trims the capacity of this <tt>ArrayList</tt> instance to be the
         * list's current size.  An application can use this operation to minimize
         * the storage of an <tt>ArrayList</tt> instance.
         */
        public void trimToSize() { 将ArrayList的容量减至最低,与元素的个数相同 这样可以节约存储空间
            modCount++;
            if (size < elementData.length) {
                elementData = (size == 0)
                  ? EMPTY_ELEMENTDATA
                  : Arrays.copyOf(elementData, size); 只取这个数组只的size大小的元素的数组
            }
        }
    //void java.util.ArrayList.ensureCapacity(int minCapacity)
        /**
         * Increases the capacity of this <tt>ArrayList</tt> instance, if
         * necessary, to ensure that it can hold at least the number of elements
         * specified by the minimum capacity argument.
         *
         * @param   minCapacity   the desired minimum capacity
         */
        public void ensureCapacity(int minCapacity) {
            int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                // any size if not default element table 如果是已经插入过值的ArrayList,那么最小扩容是任意,
                ? 0
                // larger than default for default empty table. It's already
                // supposed to be at default size.
                : DEFAULT_CAPACITY;
    
            if (minCapacity > minExpand) {
                ensureExplicitCapacity(minCapacity);
            }
        }
    
        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0) 只有现在设置的容量比之前的数组容量大才需要扩容
                grow(minCapacity);
        }
        /**
         * Increases the capacity to ensure that it can hold at least the
         * number of elements specified by the minimum capacity argument.
         *
         * @param minCapacity the desired minimum capacity
         */
        private void grow(int minCapacity) {  这里是实际进行扩容的操作
            // overflow-conscious code
            int oldCapacity = elementData.length;  这是原来的容量
            int newCapacity = oldCapacity + (oldCapacity >> 1); 原来容量的1.5倍
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity; 若是现在这个容量比你设置的那个容量要小的话,就采用你设置的那个容量,不然就设置为原来容量的1.5倍
            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);
        }
    
        private static int hugeCapacity(int minCapacity) {
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
        }
        public boolean contains(Object o) {
            return indexOf(o) >= 0;
        }
    
        public int indexOf(Object o) { 查找出元素在ArrayList中出现的第一次的位置  顺序遍历
            if (o == null) {
                for (int i = 0; i < size; i++)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = 0; i < size; i++)
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
        }
    
        public int lastIndexOf(Object o) { 查找出元素在ArrayList中出现的最后一次,沿着数组反向遍历即可
            if (o == null) {
                for (int i = size-1; i >= 0; i--)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = size-1; i >= 0; i--)
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
        }
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T[] a) {
            if (a.length < size)  如果a的长度比原ArrayList的长度要小  这个a数组就放不下原ArrayList转成成的数组
                // Make a new array of a's runtime type, but my contents:生成一个新的数组,将原来的ArrayList中的元素拷贝进去,返回
                return (T[]) Arrays.copyOf(elementData, size, a.getClass()); 
            System.arraycopy(elementData, 0, a, 0, size); 将ArrayList中的元素拷贝到a数组中,覆盖原有值
            if (a.length > size) 将a数组后面多的元素清空
                a[size] = null;
            return a;
        }
        public E remove(int index) {
            rangeCheck(index); 
            modCount++;
            E oldValue = elementData(index);
    
            int numMoved = size - index - 1; 在删除元素后,需要移动的数量
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved); 在删除index处的数据后,将所有的index后面的元素向前移动
            elementData[--size] = null; // clear to let GC do its work
    
            return oldValue;
        }
        public boolean remove(Object o) {  删除指定元素
            if (o == null) {  如果是null的话,就把数组中所有的null给删除
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
                    if (o.equals(elementData[index])) {
                        fastRemove(index);
                        return true;
                    }
            }
            return false;
        }
        private void fastRemove(int index) { 快速删除索引为index的元素,因为这里快速就是没经过检查index是否超出范围
            modCount++;                      这个方法是一个私有方法,只在类的内部调用
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved);
            elementData[--size] = null; // clear to let GC do its work
        }
        /**
         * Removes all of the elements from this list.  The list will
         * be empty after this call returns.
         */
        public void clear() {
            modCount++;
    
            // clear to let GC do its work
            for (int i = 0; i < size; i++)
                elementData[i] = null;
    
            size = 0;
        }clear操作只是将数组中所有元素置为null,然后将数组的大小(元素的个数)设置为0
        public boolean addAll(int index, Collection<? extends E> c) { 将一个集合插入到index处
            rangeCheckForAdd(index);
            Object[] a = c.toArray();
            int numNew = a.length;
            ensureCapacityInternal(size + numNew);  // Increments modCount
    
            int numMoved = size - index;
            if (numMoved > 0)  先将index后面的数据整体往后移动numNew个单位
                System.arraycopy(elementData, index, elementData, index + numNew,
                                 numMoved);
            System.arraycopy(a, 0, elementData, index, numNew); 将数据拷贝进来
            size += numNew;
            return numNew != 0;
        }
  • 相关阅读:
    算法训练 2的次幂表示
    算法训练 进制转换
    算法训练 Beaver's Calculator (蓝桥杯)
    抽签问题(不断优化)
    矩阵快速幂
    斐波那契数列
    找出最小自然数N,使N!在十进制下包含Q个0(输入Q,输出N)
    二维数组名是指针的指针吗?
    StringBuffer
    Lake Counting (POJ No.2386)
  • 原文地址:https://www.cnblogs.com/yanliang12138/p/10278896.html
Copyright © 2011-2022 走看看