ArrayList源码分析

作者: Lazy1 | 来源:发表于2017-04-21 17:05 被阅读33次
    • 可以看到我们创建ArrayLis的时候指定了大小,会创建一个默认指定大小的数组
     public ArrayList(int initialCapacity) {
            super();
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            this.elementData = new Object[initialCapacity];
        }
    
    
    • 无参的会创建一个空数组
     public ArrayList() {
            super();
            this.elementData = EMPTY_ELEMENTDATA;
        }
    
    
    • 转换成数组并且copy到elementData数组中去
    
      public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();
            size = elementData.length;
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        }
    
    
    • 测量存放数据数组的大小
    
     public void ensureCapacity(int minCapacity) {
         如果是空数组就是0,否则minExpand =10
            int minExpand = (elementData != EMPTY_ELEMENTDATA)
                // any size if real element table
                ? 0
                // larger than default for empty table. It's already supposed to be
                // at default size.
                : DEFAULT_CAPACITY;   默认大小是10
    
            if (minCapacity > minExpand) {
                ensureExplicitCapacity(minCapacity);
            }
        }
    
    
    • 进入到ensureExplicitCapacity
    
     private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
    
    
     private void grow(int minCapacity) {
            之前存放的数据大小
            int oldCapacity = elementData.length;、
            新增大小为=之前存放的数据大小+oldCapacity/2
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity < 0)
            新增之后的数据大小还小于计算之后newCapacity大小,就以传递的大小为准
                newCapacity = minCapacity;
                判断当前增加的大小是否大于 Integer.MAX_VALUE - 8
            if (newCapacity - MAX_ARRAY_SIZE > 0)
            重新计算返回Integer.MAX_VALUE或者 Integer.MAX_VALUE - 8
                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;
        }
    
    
     contains判断可以里看出,是2个循环,至于这里为什么不用加强for因为Arratlisr实现了RandomAccess
    public int indexOf(Object o) {
            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;
        }
    
    
    • get方法实现
     public E get(int index) {
            rangeCheck(index);
    
            return elementData(index);
        }
        
        
     private void rangeCheck(int index) {
            if (index >= size)
            这个异常就是大家熟悉的角标越界
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
        
        可以看到直接根据数组的角标返回因此查询比较快
         @SuppressWarnings("unchecked")
        E elementData(int index) {
            return (E) elementData[index];
        }
    
    
    • set方法实现

    ```java`

    public E set(int index, `E element) {
    rangeCheck(index);
    如果有数据就会返回当前位置的数据并且替换
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
    }

    
    
    
    - add方法
    
    ```java
    
      public boolean add(E e) {
            测量数组是否能存放不能就扩大
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            设置当前位置的数据并且集合size++
            elementData[size++] = e;
            return true;
        }
    
    
    测量大小方法
     private void ensureCapacityInternal(int minCapacity) {
     如果之前没有添加数据,是空数组那就设置数组的大小默认为10
            if (elementData == EMPTY_ELEMENTDATA) {
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
             下面这个就是上面分析的扩大数组大小的方法
            ensureExplicitCapacity(minCapacity);
        }
    
    

    System.arraycopy和``Arrays.copyOf我们查看源码可以发现Arrays.copyOf底层还是 System.arraycopy`实现拷贝的

    • remove方法
     public boolean remove(Object o) {
            if (o == 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) {
            modCount++;
            int numMoved = size - index - 1;
            if (numMoved > 0)
            重新拷贝个新的数组,从当前要删除的位置的下一位开始拷贝,此处可见删除只是重新copay的一份新的数组
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved);
            elementData[--size] = null; // clear to let GC do its work
        }
    
    • clean方法
    
       public void clear() {
            modCount++;
    
            // clear to let GC do its work  清空数组,等待GC回收
            for (int i = 0; i < size; i++)
                elementData[i] = null;
    
            size = 0;
        }
    
    

    相关文章

      网友评论

        本文标题:ArrayList源码分析

        本文链接:https://www.haomeiwen.com/subject/hmsrottx.html