ArrayList的基本原理


title: ArrayList原理解析
date: 2019-03-02 08:37:25
tags: Java基础


ArrayList的基本原理

ArrayList是我们平时编码经常用到的动态数组容器类,要想分析它的原理,我们先来看看一个简易的DynamicArray类(摘自Java编程的逻辑)

一个简易的动态数组类

public static class DynamicArray<E>{

    private static final int DEFAULT_CAPACITY = 10;

    private int size;

    private Object[] elementData;
   public Dynamicarray() {

       this.elementData = new Object[DEFAULT_CAPACITY];

   }

   public void ensureCapacity(int minCapacity){

       int oldCapacity = elementData.length;

       if(oldCapacity >= minCapacity){

           return;

       }

       int newCapacity = oldCapacity * 2;

       if(newCapacity < minCapacity){

           newCapacity = minCapacity;

       }

       elementData = Arrays.copyOf(elementData,newCapacity);

   }

   public void add(E e){
		ensureCapacity(size + 1);

       elementData[size++] = e;

   }

   public E get(int index){

       return (E) elementData[index];

   }

   public E set(int index,E e){

       E e1 = get(index);

       elementData[index] = e;

       return e1;

   }

}

在这个类中,定义了一个内部数组elementData,数组元素个数size,一个静态常量DEFAULT_CAPACITY,它表示数组的默认空间大小。这个动态数组类的操作基本都是基于内部数组element和size。ensureCapacity方法,在每次做add操作时,都会被调用,它是检查当前数组容量,并增大容量,然后根据新的容量,复制原来数组的。

ArrayList源码解析:

ArrayList的基本原理与上文中的动态数组类是差不多的,它同样有静态常量默认空间,实例变量内部数组、元素个数。同样,内部方法基本都是操作elementData这个数组,size实时记录着这个数组的大小,首先我们从add方法说起(各源码内注释已说明白,就不再叙述)。

添加方法add(E e):

public boolean add(E e) {

    //首先,调用ensureCapacityInternal方法,确保数组容量够。将当前元素个数加一,即最小容量minCapacity传入方法。

    ensureCapacityInternal(size + 1);  // Increments modCount!!

    elementData[size++] = e;

    return true;

}

检查数组容量方法ensureCapacityInternal(int minCapacity):

private void ensureCapacityInternal(int minCapacity) {

    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));

}

private static int calculateCapacity(Object[] elementData, int minCapacity) {

//如果数组为空,则返回默认值与minCapacity之间的最大值

    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

        return Math.max(DEFAULT_CAPACITY, minCapacity);

    }

    return minCapacity;

}

private void ensureExplicitCapacity(int minCapacity) {

    modCount++;
    //如果minCapacity大于当前数组的长度,就调用grow方法增大容量,

    if (minCapacity - elementData.length > 0)

        grow(minCapacity);

}

modCount++表示内部的修改次数,而这个参数与arrayList的迭代有关,下篇博客再讲解。

增大数组容量grow方法(int minCapacity):

  private void grow(int minCapacity) {

    // overflow-conscious code

    int oldCapacity = elementData.length;

    //定义一个新的容量newCapacity,它的值为当前容量右移一位,即除以2,再加上当前数组容量,即当前数组容量的1.5倍

    int newCapacity = oldCapacity + (oldCapacity >> 1);

    //如果还小于当前元素个数加一,新的容量就等于minCapacity

    if (newCapacity - minCapacity < 0)

        newCapacity = minCapacity;

    //如果newCapacity大于一个静态常量MAX_ARRAY_SIZE,就调用hugeCapacity方法,

    将newCapacity设定为Integer包装类的最大值0x7fffffff,其中MAX_ARRAY_SIZE为Integer.MAX_VALUE-8,

    减8是因为在一些vm中,在数组中会保留一些头信息,尝试分配更大的数组可能导致OutOfMemoryError:

    请求的数组大小超过VM限制

    if (newCapacity - MAX_ARRAY_SIZE > 0)

        newCapacity = hugeCapacity(minCapacity);

    // minCapacity is usually close to size, so this is a win:

    //以newCapacity为数组size,创建了一个新的数组,复制原内容,赋值给elementData

    elementData = Arrays.copyOf(elementData, newCapacity);

}
private static int hugeCapacity(int minCapacity) {

    if (minCapacity < 0) // overflow

        throw new OutOfMemoryError();

    //如果minCapacity还大于MAX_ARRAY_SIZE,就返回Integer的最大值0x7fffffff

    return (minCapacity > MAX_ARRAY_SIZE) ?

        Integer.MAX_VALUE :

        MAX_ARRAY_SIZE;

}

再来看看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);

    //将size减1,GC会回收未经使用的对象

    elementData[--size] = null; // clear to let GC do its work
    return oldValue;

}

这里modCount依旧加一。

结论

上面,我们介绍了ArrayListaddremove方法,其他方法也都是对内部数组elementData和元素个数size的操作,就不再探究了。总之,ArrayList就是一个动态数组,实现动态的原理,就是对内部的elementData、size和默认空间DEFAULT_CAPACITY进行操作。创建ArrayList时,会默认初始化一个DEFAULT_CAPACITY大小的数组。每次要做增加操作,就进行数组容量检查,若不够,就增加容量,做删除操作,size就减一,保持size实时记录当前元素个数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值