美文网首页
ArrayList原理解析

ArrayList原理解析

作者: leap_ | 来源:发表于2019-12-19 15:01 被阅读0次
    ArrayList继承关系图

    Iterable:

    实现这个接口的类可以和增强for循环一起使用

    // 返回这个类的迭代器
    Iterator<T> iterator();
    

    Collection:

    这个接口是所有集合的父接口,定义规范了所有集合的行为

    public boolean add(E object);
    public boolean addAll(Collection<? extends E> collection);
    public void clear();
    public boolean contains(Object object);
    //判断collection是否全部在当前集合中
    public boolean containsAll(Collection<?> collection);
    public boolean equals(Object object);
    public boolean isEmpty();
    public Iterator<E> iterator();
    public boolean remove(Object object);
    // 去除当前集合中collection中的元素
    public boolean removeAll(Collection<?> collection);
    // 在当前集合中保留collection中的元素(取交集)
    public boolean retainAll(Collection<?> collection);
    public int size();
    // 将这个集合中所有的数据当做数组返回
    public Object[] toArray();
    

    ArrayList:

    ArrayList的底层是一个数组,特点是增删慢,查找快,线程不安全;
    ArrayList类中的变量

    // 底层数组的默认大小
    private static final int DEFAULT_CAPACITY = 10;
    // 存放数据的个数
    int size;
    // 底层数组对象
    transient Object[] elementData;
    // 一个空的数组,用来初始化上面的elementData对象
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    

    transient:transient关键字修饰的变量不参与序列化过程

    ArrayList():
    // 给array对象赋值一个空的数组
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    

    新建一个ArrayList对象,会为底层的数组赋值一个空的obj数组

    add():
    public boolean add(E e) {
            // 判断size+1是否超过数组容量,超过就扩容
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
    
        private void ensureCapacityInternal(int minCapacity) {
            // 如果elementData是第一次在构造方法中赋值的空数组,首次初始化10个大小
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    
            ensureExplicitCapacity(minCapacity);
        }
    
        private void ensureExplicitCapacity(int minCapacity) {
            // 数组size改变的次数(存放在AbstractList中)
            modCount++;
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                // 如果当前需要的容量大于数组的实际容量,执行扩容逻辑
                grow(minCapacity);
        }
    
    //  数组最大容量 , 一些jvm需要存放一些head words
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
        //  数组扩容核心代码
        private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            // 新容量等于旧容量的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);
        }
    
        // 如果这次扩容的新大小大于数组最大值(max-8)
        private static int hugeCapacity(int minCapacity) {
            // 如果超过int的max,overflow
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            //  如果还没有超过max将新容量调整到max
            return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
        }
    

    add操作:在添加操作中,首先会判断当前size+1后是否超过底层数组的容量,如果是第一次add,将底层数组的容量默认扩容为10个大小,当第十一次添加的时候(需要的大小11>底层数组的大小10)进行扩容处理,新的底层数组大小变成旧数组的1.5倍,底层数组容量的最大值是max-8,但是如果超过这个数,还是能继续扩充到max的,当超过max就会溢出,OutOfMemoryError;

    get():
        public E get(int index) {
            rangeCheck(index);
            return elementData(index);
        }
    
        private void rangeCheck(int index) {
            if (index >= size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    

    get操作很简单,判断index是否合法,返回数组的第index个元素

    remove(int index):
     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);
            elementData[--size] = null; // clear to let GC do its work
    
            return oldValue;
        }
    

    remove操作调用了java的一个native方法,arraycopy(Object src, int srcPos, Object dest, int destPos,int length),各个参数的含义:

    • src:需要复制的数组
    • srcPos:src的开始下标
    • dest:返回的结果数组
    • destPos:dest的开始下标(从哪里开始复制)
    • length:复制的长度
      remove的思路是将下标index的元素丢弃,然后将index到size-1的元素通过arraycopy全部向前移动一个单位,将最后一个元素置为null等待gc回收
    remove(Object o):
     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;
        }
    

    remove(obj)通过循环找到obj对象的index,再通过index和arraycopy删除元素,fastRemove同上面的remove(index),只不过省去了保存obj的逻辑;

    clear()
        public void clear() {
            modCount++;
    
            // clear to let GC do its work
            for (int i = 0; i < size; i++)
                elementData[i] = null;
    
            size = 0;
        }
    

    简单易懂

    相关文章

      网友评论

          本文标题:ArrayList原理解析

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