java ArrayList实现原理解析

主要参照jdk1.6,1.7 。
为了便于理解,对源码进行了一定改造,并按层次进行解析。
本文只讨论关键的方法。

主要实现的接口
Iterable:返回一个可迭代的类。
Collection:集合类,定义了一系列处理集合的方法。比如add,remove,size等。

主要的父类
AbstractList:根据jdk版本的不同,会有一些具体的实现方法。不过最需要关注的一点是这个类定义了modCount。

ArrayList的算法结构
本体是一个数组,java中定长的那个数组。
所以说,ArrayList类的本体是这个。

/**
 * 
 * @author nayi224
 * https://blog.csdn.net/nayi_224
 * 2018-5-14下午10:27:51
 */
public class NayiArrayList1 {

    private Object[] element;

    public NayiArrayList1(){
        this(10);
    }

    public NayiArrayList1(int size){
        this.element = new Object[size];
    }

}

ArrayList通过内部的代码使其成为一个可变长的数组。
当添加一个元素时,若长度足够,会直接添加,否则会将数组复制为一个1.5倍长+1的数组。若在数组中间添加或删除一个元素,则会对这个对象之后的部分向后复制。
ArrayList中还有一个size属性来记录当前储存数据的长度,用以辅助上述操作。

简易实现代码:

import java.util.Arrays;

/**
 * 
 * @author nayi224
 * https://blog.csdn.net/nayi_224
 * 2018-5-14下午10:45:12
 */
public class NayiArrayList2 {

    private Object[] elementData;

    private int size;

    public NayiArrayList2(){
        this(10);
    }

    public NayiArrayList2(int size){
        this.elementData = new Object[size];
    }

    public boolean add(Object e){
        ensureCapacity(size + 1);
        elementData[size++] = e;
        return true;
    }

    public Object remove(int index) {
        // RangeCheck(index);

        // modCount++;
        Object oldValue = elementData[index];

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index + 1, elementData, index,
                    numMoved);
        elementData[--size] = null; // Let gc do its work

        return oldValue;
    }

    public Object get(int index) {
        //RangeCheck(index);

        return elementData[index];
    }

    /**
     * 该方法使数组有了一个自增机制
     * @param minCapacity 新数组的长度
     */
    public void ensureCapacity(int minCapacity) {
        // modCount++;
        int oldCapacity = elementData.length;
        if (minCapacity > oldCapacity) {
            Object oldData[] = elementData;
            int newCapacity = (oldCapacity * 3) / 2 + 1;
            if (newCapacity < minCapacity)
                newCapacity = minCapacity;
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    }

}

我这里只实现了add,remove,get三个方法,并且省略了全部校验。
可以很清晰的看出,get方法只是按照下标去取值,效率是非常高的。add与remove方法首先会有一个运算,这几乎不会影响效率。但是它需要复制所修改位置之后的全部元素,甚至可能需要对原数组进行全量复制,这个效率可能会非常差。

一些关键的校验

    private void RangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(
            "Index: "+index+", Size: "+size);
    }

我们最熟悉的数组下标越界。

    public NayiArrayList2(int size){
        if (size < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                    size);

        this.elementData = new Object[size];
    }

初始化时的校验,数组的长度不能是负的。

迭代机制
我在https://blog.csdn.net/nayi_224/article/details/80102394这篇文章里做过比较完整的整理。

fast-fail机制
主要通过modCount这个属性实现。实现原理为在对elementData进行结构上的修改时,进行modCount++。在迭代的时候检查modCount的值,若modCount值发生了变化,则说明elementData的结构发生了变化,需要跑出异常。注意,在并发情况下,这个机制会返回错误的结果。官方的建议是,这个机制应该只用来调试,而不是用它来真正的控制异常。
具体的讨论同样在这篇文章中进行了讨论https://blog.csdn.net/nayi_224/article/details/80102394

ArrayList最核心的部分只有这些了,剩下的只是在堆代码,建议自行查看。
如果不知道查看方法的话。写上这句话java.util.ArrayList a;按住ctrl再左键点击ArrayList。

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/nayi_224/article/details/80316305
文章标签: java基础
个人分类: java
上一篇java System.arraycopy 复制数组
下一篇oracle lead/lag 函数 ignore nulls 功能在11g以下版本的实现
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭