【每日一篇】JAVA集合详解----ArrayList(上)

    前文链接List接口详解

    今天把明天的份也写了如何?

    ArrayList是JAVA开发者最常用的列表没有之一啦,这个类通过继承虚基类AbstractList的方式实现了List接口,顺便也实现了Collection接口及Lterable接口,以上三个接口的用处前文均已说过,这里不废话。

    同时ArrayList类还实现了RandomAccess(标记接口,用于队列,实现该接口表示支持快速随机访问)、Cloneable(同样是标记接口,实现该接口表示重写了Object.clone()方法,可以合法的通过clone()方法复制)、serializable(标记接口,实现该接口使此类可序列化,否则会在序列化时保存,配合serialVersionUID可以标识类版本)

    ArrayList,顾名思义是数组列表的意思,作为List接口的可调大小数组实现,这个类实现了所有可选的列表操作,允许包括null在内的所有数组元素,提供了调整内部数组大小的方法。能够以O(n)速度实现绝大多数操作,值得注意的是ArrayList是不同步的,而隔壁的Vector则是同步的。可以通过List list = Collections.synchronizedList(new ArrayList(...));语句来加锁。

    值得注意的是,ArrayList的迭代器是“快速失败“的,快速失败的详解可以参考快速失败,过几天我自己也会写一篇迭代器的解析,因为Literator(迭代器)在被创建之后,任何不使用该迭代器的remove()或者add()改变ArrayList结构的方法都会导致该错误,这个特性同时也导致了我们不能在普通的for循环中调用list的remove()方法删除元素。jdk1.8后,这种情况我们可以使用removeAll()方法更优雅的解决。

    接下来是ArrayList一些比较有趣的常量和方法介绍:

      常量:

    1.serialVersionUID,没什么好说的,用于序列化时标明类版本

    2 DEFAULT_CAPACITY=10,默认的初始化容量,大小为10个元素

    3 EMPTY_ELEMENTDATA,空元素,初始化时使用

    4.DEFAULTCAPACITY_EMPTY_ELEMENTDATA 默认容量空元素数组,初始化时使用

    5.elementData 元素数组,ArrayList数组的数据保存在这个数组中,放入第一个元素时如果是空数组也就是等于上面的EMPTY_ELEMENTDATA,会被给与一个初始大小(capacity)

    6.size,emmm不废话

    方法:

    1.构造函数ArrayList(),有三种入参,输入int的话会按照输入的大小初始化一个数组,不输入或者输入0会让elementData =DEFAULTCAPACITY_EMPTY_ELEMENTDATA,也就是空数组啦,输入Collection(集合的话)会调用Collection.toArray()方法转成数组,如果转失败(结果不是Object[])的话就没下文,成功的话就调用Arrays.copyOf方法复制这个数组到elementData数组。

    2.trimToSize()方法。将elementData 的大小调整到size大小,用来节约空间,值得注意的是这里用的还是Arrays.copyOf方法,下一篇就写Arrays吧。同样值得注意的是调整大小之前这个方法还将modCount(ArrayList未声明,直接继承于父类AbstractList)值+1了,这个操作的解释见modCount

    3.ensureCapacity(int size)、ensureCapacityInternal()、ensureExplicitCapacity()方法,这一套素质三连可以添加elementDate的大小,这里还做了一个复杂判断让小数组的大小尽量为默认值(10),反正最后会调用grow()方法扩大大小

    4.grow()方法,这里要提到一个新常量MAX_ARRAY_SIZE,大小为INTEGER.MAX_SIZE-8,这个常量是ArrayList大小可以达到的最大值,某些虚拟机要占用一下头字节还会再少一点,反正超过了就报OOM错误啦。

        回到代码里,这个方法还用了位运算,挺有趣的贴一下

 private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        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);
    }private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

反正右移一位是除2,就是说会扩容1.5倍,如果还是不够大就是按照输入的大小来,如果大小溢出的话就调用hugeCapacity,反正数组大小不会超过Integer的最大值啦

    5.size(),isempty(),方法就是用了一下size这个变量

    6.index(),lastindexof(),这两个方法分别是从数组的前后方做遍历,不提

    7.clone()方法,先调用super.clone(),然后用Arrays.copyOf()方法(怎么又是你)复制关键的数组,然后把modCount置空

    8.toArray()方法,无参数的话还是Arrays.copyOf(),有参数的话就比较有意思,如下:

    

    @SuppressWarnings("unchecked")
    public  T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

    这里调用的是System.arraycopy()方法,是一个native方法,emmmm等我看Arrays的时候再看这个的解释,然后还判断了一下数组的长度,如果超过的话就将a[size]置空,这个的意义何在?不太理解    

    9.elementDate()方法,project方法,返回数组指定位置元素,未验证安全

    10.get()方法,验证index范围后调用elementDate()方法

    11.set(),验证范围后直接操作数组


你可能感兴趣的:(JAVA)