手动实现ArrayList

Posted cmg219

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手动实现ArrayList相关的知识,希望对你有一定的参考价值。

目标:手动实现一个ArrayList,然后分析JDK ArrayList的源码

/**
 * rangeCheck(),检查数组下标是否越界;
 * add(),在某个下标位置添加元素;
 * resize(),动态扩容,当数组容量满或者空闲整个数组的3/4时,重新定义容量;
 * get(),获取某个位置的元素值;
 * set(),设置某个下标的元素值;
 * remove(),移除某个下标对应的值;**/
public class MyArrayList<E> {
    private int size;//数组长度
    private Object elementData[];//保存数组元素
    //无参构造函数
    public MyArrayList(){
        this.elementData=new Object[10];
    }
    //带参构造函数
    public MyArrayList(int initialCapacity){
       if(initialCapacity>=0){
            this.elementData=new Object[initialCapacity];
        }else{
            throw new RuntimeException("非法输入初始化容量:"+initialCapacity);
        }
    }
    public int getSize(){
        return size;
    }
    public int getCapacity(){
        return elementData.length;
    }
    public boolean isEmpty(){
        return size == 0;
    }

    public void rangeCheck(int index){
        if(index < 0 || index >= size)
            throw new IllegalArgumentException("Index is Illegal!");
    }

    public void add(int index,E e){
        if(index<0||index>size){
            throw new IllegalArgumentException("index is illegal!");
        }
        if(size==elementData.length){
            resize(elementData.length);
        }
        //把index后的元素后移
        for(int i=size-1;i>index;i--){
            elementData[i+1]=elementData[i];
        }
        elementData[index]=e;
        size++;
    }
    //末尾添加
    public  void add(E e){
        add(size,e);
    }
   private void resize(int minCapacity){
        int newCapacity=minCapacity+minCapacity<<1;
        Object[]newData=new Object[newCapacity];
        for(int i=0;i<size;i++){
          newData[i]=elementData[i];
        }
        elementData=newData;
   }
    public E remove(int index){  // remove data[index] and return the value
        rangeCheck(index);
        E res = (E) elementData[index];
        for(int i = index; i < size-1; i++){
            elementData[i] = elementData[i+1];
        }
        size--;
        elementData[size] = null;//loitering objects  != memory  leak
        return res;
    }
   public E get(int index){
        rangeCheck(index);
        return (E)elementData[index];
   }
   public void set(int index,E e){
        rangeCheck(index);
        elementData[index]=e;
   }

    @Override
    public String toString() {
        return "MyArrayList{" +
                "elementData=" + Arrays.toString(elementData) +
                '}';
    }
}

以上是我自己实现的MyArrayList,数组的扩容是新建一个数组来代替原来数组,阅读ArrayList源码后发现,它是通过调用ensureCapacityInternal方法进行扩容,每次扩容为原来大小的1.5倍,但是当第一次添加元素或者刘表重元素个数小于10的话,列表容量默认为10.
以add方法为例,add的源码为:

  public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 确保内部数组有足够的空间
        elementData[size++] = e; //将元素加入到数组的末尾,完成添加
        return true;
    }

如果继续往下Debug

  private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    //数组若是等于空且数组元素个数小于10,就会将数组长度设置为10,大于10则为minCapacity
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    //将数组扩容
    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);
    }

可以看到,只有在数组容量不满足需求时,会调用Arrays.copyOf方法拷贝数组,所以初始化一个大小合理的数组队性能很有帮助。

以上是关于手动实现ArrayList的主要内容,如果未能解决你的问题,请参考以下文章

手动实现一个简单的ArrayList

ArrayList.add 不适用于 AsyncTask

在 Arraylist 的 listview 的 listitem 上显示值

片段之间的静态 ArrayList

Java 集合学习笔记:ArrayList

手动实现 容器