纯手写arrayList

arrayList 底层其实就是数组。今天有时间手写一个arrayList 加深对集合的理解。废话不多说,直接手写

1.定义集合接口泛型:MyArrayListInterface

package collection.list;

/**
 * 定义接口泛型
 *
 * @param <E>
 */
public interface MyArrayListInterface<E> {
    /**
     * 新增
     */
    boolean add(E object);

    /**
     * 根据下标新增
     */
    boolean add(int index, E object);

    /**
     * 更新下标
     */
    boolean set(int index ,E object);

    /**
     * 根据下标删除
     */
    Object remove(int index);

    /**
     * 集合元素大小
     */
    int size();

    /**
     * 根据下标查询元素
     */
    E get(int index);

    /**
     *
     * 判断集合是否为空
     */
    boolean isEmpty();

}

2.实现这个集合接口:MyArrayList

package collection.list;

import java.util.Arrays;

/**
 * 手写arrayList
 * 底层是数组实现的,线程不安全
 */
public class MyArrayList<E> implements MyArrayListInterface<E> {

    //底层数组,来存放数据
    private Object[] elementData;

    //默认数组容量10
    private static final int DEFAULT_CAPACITY = 10;

    //记录实际ArrayList大小,这里大小其实是"有数据"的组数大小
    private int size;

    //默认初始化容量为10
    public MyArrayList() {
        this(DEFAULT_CAPACITY);
    }

    //初始化new 构建的时候,ArryList指定数组初始的容量
    public MyArrayList(int initialCapacity) {
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("初始化容量不能小于0");
        }
        //数据大小初始化
        elementData = new Object[initialCapacity];
    }

    /**
     * 添加集合元素
     *
     * @param object
     * @return
     */
    public boolean add(E object) {
        //添加元素的时候,先要检查一下。数组实际存放元素大小是否大于数组定义的大小,如果是就扩容
        ensureCapacityInternal(size + 1);
        //赋值
        elementData[size++] = object;
        return true;
    }

    /**
     * 检查元素大小,是否需要扩容
     *
     * @param minCapacity
     * @return
     */
    public void ensureCapacityInternal(int minCapacity) {
        //实际元素大小>= 定义的数组大小,这个时候需要扩容,每次扩容为之前的1.5倍大小。
        if (size >= elementData.length) {
            int oldCapcity = elementData.length;
            int newCapcity = oldCapcity + oldCapcity >> 1;//1+ 1/2
            if (newCapcity < minCapacity) { //如果扩容定义容量之后,还是小于实际要存放的容量。即扩容容量为实际容量
                newCapcity = minCapacity;
            }
            elementData = Arrays.copyOf(elementData, newCapcity);//将老数组copy出一个新数组。newCapcity 是复制长度
        }

    }

    /**
     * 指定位置插入元素,位置索引必须有实际用过的元素
     *
     * @param index
     * @param object
     * @return
     */
    public boolean add(int index, E object) {//index 一定是实际元素的index
        rangeCheck(index);//检查数组索引是否小标越界
        ensureCapacityInternal(size + 1);//是否需要扩容
        //各个参数说明:
        // 1.数组1 2.源数组1的开始复制索引位置 3.目标数组2 4.目标数组的开始被覆盖的索引位置 5.源数组复制长度
        //注意
        // 源的起始位置+长度不能超过末尾
        // 目标起始位置+长度不能超过末尾
        // 且所有的参数不能为负数
        //实际就是复制一个新数组,中间留个空位置,给将要插入的原始
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        elementData[index] = object;
        return true;
    }

    /**
     * 根据下标替换更新
     *
     * @param index
     * @param object
     * @return
     */
    public boolean set(int index, E object) {
        rangeCheck(index);//检查数组索引是否小标越界
        elementData[index] = object;
        return true;
    }

    /**
     * 删除元素
     *
     * @param index
     * @return
     */
    public E remove(int index) {
        //下标是否越界
        rangeCheck(index);
        //1.先查询一下要删除的元素
        E e = get(index);
        //删除元素
        //先计算要删除元素的index 后面的元素长度
        int numMoved = size - index - 1;
        if (numMoved > 0) { //numMoved = 0 说明移除的就是最后一个元素
            System.arraycopy(elementData, index + 1, elementData, index, numMoved);
        }
        //将最后一个元素为为空,并将长度-1
        elementData[--size] = null;//只能remove 能让元素变成未使用状态
        return e;
    }

    /**
     * 返回元素大小
     *
     * @return
     */
    public int size() {
        return size;
    }

    /**
     * 根据下标取元素
     *
     * @param index
     * @return
     */
    public E get(int index) {
        return (E) elementData[index];
    }

    /**
     * 检查索引是否下标越界
     */
    public void rangeCheck(int index) {
        if (index > size || index < 0) { //说明这个index 只能对有数据(元素用过)的index 进行指定插入。
            throw new IndexOutOfBoundsException("下标越界了");
        }
    }

    /**
     * 判断元素是否为空
     */
    public boolean isEmpty() {
        return size == 0;
    }
}

3.重点总结

一、2个重要的方法:

  1. Arrays.copyOf(elementData, newCapcity)
  2. System.arraycopy(elementData, index, elementData, index + 1, size - index);
    用于数组扩容时和数组的移动,数组复制。
    二、新增和删除的逻辑:
    1.新增:先判断是否越界下标 --> 再判断是否需要扩容 --> 再移动数组实现复制。
    2.删除:先判断是否越界下标–>再移动数组实现复制–>将元素变空。

三、需要注意的点:
1.index 是实际用过的数组元素的下标
2.size 是实际用过的数组元素的大小

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值