美文网首页
手写一个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