美文网首页
手写一个ArrayList的集合类

手写一个ArrayList的集合类

作者: 生不悔改 | 来源:发表于2022-03-07 21:37 被阅读0次

一、ArrayList集合的原理

看过ArrayList源码的小伙伴都知道,ArrayList集合的底层是用的数组的结构实现的,那我们今天就尝试自己动手造一个属于自己的CommonList集合类,从而更好的理解ArrayList的底层是如何实现的。

二、CommonList集合的构成

首先我们需要构造两个成员变量,一个是Object[]数组,一个int类型的数组里面的元素个数
我们要实现方法有:
加入方法:

/**
* 加入操作
*/
public void add(T t) ;

删除方法:

/**
* 删除操作
*/
public boolean remove(T t) ;

查询方法:

/**
* 查询操作
*/
public T get(int index) ;

包含方法:

/**
* 是否包含某一个元素操作
*/
public boolean isContain(T t) ;

获取集合元素个数的方法:

/**
* 获取集合长度的方法
*/
public int length()

三、开始代码实现:

/**
 * @author:
 * @date: 2022/3/7 10:03
 * @description:
 */
public class CommonList<T> {

    /**
     * 数组成员变量
     */
    private T[] elementData;

    /**
     * 数组元素个数
     */
    private int elementCount;

    /**
     * 默认初始化长度
     */
    private int default_capacity = 10;

    /**
     * 带参构造
     *
     * @param capacity
     */
    public CommonList(int capacity) {
        this.elementData = (T[]) new Object[capacity];
        this.elementCount = 0;
    }

    /**
     * 无参构造
     */
    public CommonList() {
        this.elementData = (T[]) new Object[default_capacity];
        this.elementCount = 0;
    }

    /**
     * 判断当前数组是否为空
     *
     * @return
     */
    public boolean isEmpty() {
        return this.elementCount == 0;
    }

    /**
     * 加入操作
     *
     * @param t
     */
    public void add(T t) {
        // 当前数组元素个数等于数组的长度,需要扩容
        if (elementCount == elementData.length) {
            reSize(2 * elementCount);
        }
        // 当前位置插入一个对象
        elementData[elementCount] = t;
        // 数组长度+1
        this.elementCount = this.elementCount + 1;
    }

    /**
     * 加入指定位置操作
     *
     * @param index
     * @param t
     */
    public void add(int index, T t) {
        // 校验参数和数组长度
        if (index >= elementCount) {
            throw new IllegalArgumentException("集合长度没有那么长");
        }
        // 当前数组元素个数等于数组的长度,需要扩容
        if (elementCount == elementData.length) {
            reSize(2 * elementData.length);
        }
        // 给数组增加一个空对象元素
        elementData[elementCount] = null;
        // 从数组增加的最后一个null位置开始遍历,然后将所有的元素向后挪一位,空出来位置我们插入我们的对象
        for (int i = elementCount; i > index - 1; i--) {
            elementData[i] = elementData[i - 1];
        }
        // 给空出来的这位赋值操作
        elementData[index] = t;
        // 当前数组长度+1
        this.elementCount = this.elementCount + 1;
    }

    /**
     * 获取集合长度的方法
     *
     * @return
     */
    public int length() {
        return elementCount;
    }

    /**
     * 获取index位置的对象
     *
     * @param index
     * @return
     */
    public T get(int index) {
        // 校验参数和数组长度
        if (index >= elementCount) {
            throw new IllegalArgumentException("集合长度没有那么长");
        }
        // index从0开始
        return elementData[index];
    }

    /**
     * 删除集合元素
     *
     * @param t
     * @return
     */
    public void remove(T t) {
        for (int i = 0; i < elementCount; i++) {
            if (elementData[i].equals(t)) {
                remove(i);
            }
        }
        // 如果删除后的元素个数小于数组的四分之一长度,数组长度缩容一半
        if (elementCount < elementData.length / 4) {
            reSize(elementData.length / 2);
        }
    }

    /**
     * 删除指定位置元素,并返回删除后的数组集合
     *
     * @param index
     * @return
     */
    private Object[] remove(int index) {
        // 校验参数和数组长度
        if (index >= elementCount) {
            throw new IllegalArgumentException("集合长度没有那么长");
        }
        // 从准备删除的地方往后遍历
        for (int i = index; i < elementCount; i++) {
            T temp = elementData[i + 1];
            elementData[i] = temp;
        }
        this.elementCount = this.elementCount - 1;
        return elementData;
    }

    /**
     * 校验当前集合中是否包含某一个元素
     *
     * @param t
     * @return
     */
    public boolean isContain(T t) {
        // 遍历所有元素,比较元素与参数的值
        for (int i = 0; i < elementCount; i++) {
            if (elementData[i].equals(t)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 集合扩容,缩容
     * 在新增,删除的时候需要加入扩容,缩容操作
     *
     * @param newCapacity
     */
    private void reSize(int newCapacity) {
        // 创建一个临时数组接收原来的数组
        T[] temp = elementData;
        // 新创建一个新的扩容数组指向原来的数组
        elementData = (T[]) new Object[newCapacity];
        // 将原来数组里面的数据给赋值到新的数组中
        for (int i = 0; i < temp.length; i++) {
            elementData[i] = temp[i];
        }
    }
}

里面好像没有遍历的方法,其实这个也是可以实现的。需要实现Iterable接口,并且还需要自己写一个iterator的实现类,去实现里面的接口方法。

四、测试:

public class CommonListTest {
    public static void main(String[] args) {
        CommonList<String> list = new CommonList<>(3);
        list.add("嘿嘿");
        list.add("哈哈");
        list.add("嘻嘻");
        list.add(1,"噢噢");

        // 能这样写是因为CommonList实现了Iterable接口
        for (String s: list) {
            System.out.println(s);
        }
        System.out.println(list.isContain("啦啦"));

        System.out.println("=======================");
        list.remove("哈哈");

         // 最原始的遍历方法
        for(int i=0;i<list.length();i++){
            System.out.println(list.get(i));
        }
    }
}

测试结果:

嘿嘿
噢噢
哈哈
嘻嘻
false
=======================
嘿嘿
噢噢
嘻嘻

五、总结:

以上就实现了我们自己的ArrayList了,里面包含了无参构造,有参构造,list集合的基本的增删查的操作,以及动态的扩容操作。
或许你会疑问,既然jdk给我们封装好了数据结构,我们为何要自己动手去实现,其实你自己实现一遍更加能体会到其中的设计原理,其次就是当我们的业务场景需要一种数据结构如果jdk自带的数据结构无法满足的时候,我们可以尝试自己去实现一个,更加贴近业务的数据结构,并解决问题。

相关文章

网友评论

      本文标题:手写一个ArrayList的集合类

      本文链接:https://www.haomeiwen.com/subject/adtorrtx.html