集合框架之ArrayList详解

ArrayList相当于一个动态数组,可以根据需要改变其数组长度。

ArrayList的属性分析

    // 序列化id  
    private static final long serialVersionUID = 8683452581122892189L; 
    // 存储arraylist元素的数组缓冲区
    private transient Object[] elementData;  
    // 当前数组长度  
    private int size; 
    //数组的最大尺寸,有些虚拟机在数组中存储一些数据头
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 

ArrayList的继承关系 :  

    public class ArrayList<E>
    extends AbstractList<E>  //父类
    implements List<E>, RandomAccess, Cloneable, Serializable  //接口

一 :由于他继承了AbstractList抽象类,AbstractList又继承了List接口。故ArrayList对象中存在List接口增删改查操作。

二:ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。

三,ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。

四,ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。当然会有transisent关键字限制变量

源码分析

三种构造函数

//构造函数一
public ArrayList() {
        this(10);
        //调用ArrayList(10) 默认初始化一个大小为10的object数组。
    }

//构造函数二
public ArrayList(int initialCapacity) {    
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
         //如果用户初始化大小小于0抛异常,否则新建一个用户初始值大小的object数组。                                      
        this.elementData = new Object[initialCapacity];
    } 

//构造函数三
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // 当c.toArray返回的不是object类型的数组时,进行下面转化。
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

增添:add(Object obj)方法

 
 
//1-----------------------
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 加入元素前检查数组的容量是否足够
        elementData[size++] = e;
        return true;
    }
//2----------------------- 
private void ensureCapacityInternal(int minCapacity) {
        modCount++;
        // 如果添加元素后大于当前数组的长度,则进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    } 
//3-----------------------  
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //将数组的长度增加原来数组的一半。
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
            //如果扩充一半后仍然不够,则 newCapacity = minCapacity;minCapacity实际元素的个数。
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
            //数组最大位2^32
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }   

注意此处的modcount计数器:他是一个记录arraylist对象操作次数的变量。

那么记录他有什么用? 

1. List有个迭代器
2. 在迭代的过程中,每次都要查一下modCount是否变化
3. 如果变化了,迭代器在处理时可能出现不可预知的情况。因此只要这个值变化了,迭代器就抛出异常

4. 所以modCount的作用是迭代器在遍历时做线程安全检查的。

补充一点add(int index,Object obj)的代码解析:

add(int index,Object obj){
    rangeCheckForAdd(index);
    //判断index是否在数组下标中    
    ensureCapacityInternal(int mincapacity)
    //检查是否需要扩容
    System.arrayCopy(object str ,int strpos ,object dest ,int destpos,int length )
    elementdata[index]= obj;
    size++;
}

这里必须要提一下System.arrayCopy()参数列表

object str:源数组;int strpos: 要复制数组的起始点;object dest:目标数组;int destpos:目标数组的起始get点i;

int  length:要被复制的数组长度    

删除源码:remove(int index)

public E remove(int index) {
        rangeCheck(index);
//如果index>=size抛出异常
        modCount++;
        E oldValue = elementData(index);
//获取删除元素的值
        int numMoved = size - index - 1;
        //将index后面所有的元素往前移一位。
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // Let gc do its work
//返回要删除的原数。
        return oldValue;
    }

remove(object obj):

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;
    }

fastRemove与Remove区别:

 // 快速删除第index个元素
    private void fastRemove(int index) {
         modCount++;
         int numMoved = size - index - 1;
         // 从"index+1"开始,用后面的元素替换前面的元素。
         if (numMoved > 0)
             System.arraycopy(elementData, index+1, elementData, index,
                              numMoved);
         // 将最后一个元素设为null
         elementData[--size] = null; // Let gc do its work
     }

remove方法首先查找要删除对象的index,然后调用fastRemove方法将index后边的对象往前复制一位,并将数组中的最后一位元素设置为null,释放对象的引用

这里有个小知识点:为什么要分开讨论null的情况呢?

因为查找时候用的比较方法<equals()>是比较的对象的值。


完结撒花~这篇博客是用健康写成的。外面下着雨,只穿着短袖,在图书馆发抖。

参考文章链接:https://blog.csdn.net/u013309870/article/details/72519272

猜你喜欢

转载自blog.csdn.net/weixin_42126680/article/details/80272857