注:为方便理解,分为三个版本,每个版本在上一个的基础上扩展,如果你有足够的基础,可以直接翻到最下面看最终版本代码,我会详细注释

内部方法与变量

add(),set(),get(),remove(),empty(),size(),checkRank(),toString()
size,elementData [],DEFAULT_CAPACITY

核心问题

问题 方法
列表的存储结构是什么? object型数组
如果扩展列表? 新建一个更大的数组取代原数组
如何适用所有类型元素 设置泛型
如何删除元素 让目标元素后面的元素依次往前挪,最后一个设为null

以上都是实现ArrayList的指导思想,接下来我们直接上代码

第一版

package collection;

/**
 * 自定义实现一个ArrayList
 */
public class MyArrayList {
    //存储元素的数组
    private Object [] elementData;
    //当前元素的个数
    private int size;  
    //数组默认大小
    private final static int DEFAULT_CAPACITY=10;
    
    public MyArrayList(int capacity){
        elementData=new Object[capacity];
    }
    //当没有设置列表大小时,默认为10
    public MyArrayList(){
        elementData=new Object[DEFAULT_CAPACITY];
    }
    //每加一个元素,先把元素放在size位置处(因为此时数组中最后一个元素位于size-1处),然后size++
    public void add(Object object){
        elementData[size++]=object;
    }
    
    //将数组转换为列表的样式输出,
    @Override
    public String toString() { 
        StringBuilder stringBuilder=new StringBuilder("[");
        for(int i=0;i<size;i++) {
            stringBuilder.append(elementData[i]);
            stringBuilder.append(",");
        }
        //现在stringBuilder中最后一个字符时逗号,我们将它转换为]号
        stringBuilder.setCharAt(stringBuilder.length()-1,']');
        return stringBuilder.toString();
    }

    public static void main(String[] args){
        MyArrayList myArrayList =new MyArrayList();
        myArrayList.add("a");
        
        System.out.println(myArrayList);
        for(int i=0;i<5;i++){
            myArrayList.add("a"+i);
        }
        System.out.println(myArrayList);

    }
}


效果如图

但是明显有很多问题,除了方法少之外,还有数组越界没有检查,而且不能设置泛型


第二版

package collection;

/**
 * arraylist数组扩容add(),泛型,size,empty
 */
//设置泛型比较简单,直接在类名后加,并且修改传入元素的类型名(add())
public class MyArrayList02<E> {
    private Object [] elementData;
    private int size;
    private final static int DEFAULT_CAPACITY=10;

    public MyArrayList02(int capacity){
        elementData=new Object[capacity];
    }
    public MyArrayList02(){
        elementData=new Object[DEFAULT_CAPACITY];
    }
    
    //边界检查,当实际容量(size)达到了数组最大容量之后
    //我们将新建一个比原来大1/2的数组,然后再赋给原来的数组
    public void add(E object){
        if(size==elementData.length){
            Object [] newArray=new Object[elementData.length+elementData.length<<1];
            System.arraycopy(elementData,0,newArray,0,elementData.length);
            elementData=newArray;
        }
        elementData[size++]=object;
    }
    //获得列表长度
    public int size(){
        return size;
    }
    //判定是否为空
    public boolean empty(){
        if(size==0){
            return true;
        }
        return false;
    }
    @Override
    public String toString() {
        StringBuilder stringBuilder=new StringBuilder("[");
        for(int i=0;i<size;i++) {
            stringBuilder.append(elementData[i]);
            stringBuilder.append(",");
        }
        stringBuilder.setCharAt(stringBuilder.length()-1,']');
        return stringBuilder.toString();
    }

    public static void main(String[] args){
        MyArrayList03<String> myArrayList02 =new MyArrayList03<>();
        for(int i=0;i<20;i++) {
            myArrayList02.add("a"+i);
        }
        System.out.println(myArrayList02);
        System.out.println("数组长度:"+myArrayList02.size());
        System.out.println("数组是空吗?"+myArrayList02.empty());
    }
}


原数组默认只有10,自动将数组扩容,新增大小为原来的1/2,用移位的方法获得,这也是ArrayList源码中使用的方法,并且新增了size(),empty()方法

但是,依旧有问题,比如新建一个空列表~


第三版

package collection;

/**
 * set,get,checkRank边界检查,remove
 */
public class MyArrayList03<E> {
    private Object [] elementData;
    private int size;
    private final static int DEFAULT_CAPACITY=10;
    //这里表示传入有容量的列表
    public MyArrayList03(int capacity){
        if(capacity<0){
            throw new RuntimeException("容量不能为负");
        }
        elementData=new Object[capacity];
    }
    //这里是没有传参的列表,默认容量是10
    public MyArrayList03(){
        elementData=new Object[DEFAULT_CAPACITY];
    }
    //添加元素,先判定是否到了数组边界,如果到了就扩容,然后添加一个位置
    public void add(E object){
        if(size==elementData.length){
            Object [] newArray=new Object[elementData.length+elementData.length<<1];
            System.arraycopy(elementData,0,newArray,0,elementData.length);
            elementData=newArray;
        }
        elementData[size++]=object;
    }
    //移除元素,将目标元素后面的元素挨个赋给前一位,这样会导致最后一位和倒数第二位相同,size--不输出最后一位
    //为了避免意外错误,我们把最后一位手动设为空
    public void remove(int index){
        //a,b,c,d,e,f
        //a,b,c,e,f
        checkRank(index);
        int moveElement=size-index-1;
        if(moveElement>0) {
            elementData[size] = null;
            System.arraycopy(elementData, index + 1, elementData, index, moveElement);
        }
        size--;
        
    }
    @Override
    public String toString() {
        StringBuilder stringBuilder=new StringBuilder("[");
        if(size==0)stringBuilder.append("]");
        //这里以size为输出大小,所以以后的add或者remove等只需要修改size就可以获得位置或者删除位置
        for(int i=0;i<size;i++) {
            stringBuilder.append(elementData[i]);
            stringBuilder.append(",");
        }
        //将最后一个逗号改为"]"
        stringBuilder.setCharAt(stringBuilder.length()-1,']');
        return stringBuilder.toString();
    }
    
    public E get(int index){
        checkRank(index);
        return (E)elementData[index];
    }
    public void set(E e,int index){
        checkRank(index);
        elementData[index]=e;
    }
    //检查数组是否越界
    public void checkRank(int index){
        if(index<0||index>size-1){
            throw new ArrayIndexOutOfBoundsException("索引不合法");
        }
    }
    //获得列表长度
    public int size(){
        return size;
    }
    //判定是否为空
    public boolean empty(){
        if(size==0){
            return true;
        }
        return false;
    }
    public static void main(String[] args){
        MyArrayList03<String> myArrayList03 =new MyArrayList03<>();
        System.out.println(myArrayList03);
        for(int i=0;i<1;i++)
            myArrayList03.add("a"+i);
        System.out.println("添加1个元素后列表长度为"+myArrayList03.size());
        System.out.println("列表元素 "+myArrayList03);
        myArrayList03.remove(0);
        System.out.println("删除第一个元素后 "+myArrayList03);
    }
}

进行了更多的边界检查,同时新增了remove(),get,set等使用方法,也改进了toString方法