使用java模拟实现ArrayList

这篇博客详细介绍了如何使用Java模拟实现ArrayList。从定义List接口开始,接着创建ArrayList类并实现自定义接口。文章重点分析了ArrayList的重要方法,包括其内部的两个关键变量elementData和size,各种构造方法,特别是扩容方法grow()的工作原理,以及元素的添加操作。
摘要由CSDN通过智能技术生成

1. 定义一个List接口

package com.cqc.ArrayList;

/**
 * 线性表接口
 * 和存储结构无关
 * @author Administrator
 *
 */
public interface List {
    //返回线性表的大小,即数据元素的个数
    public int size();

    //返回线性表中序号为i的数据元素
    public Object get(int i);

    //判断线性表是否为空,空为true,否则为false
    public boolean isEmpty();

    //判断线性表是否包含数据元素e
    public boolean contains(Object e);

    //返回数据元素e在线性表中序号
    public int indexOf(Object e);

    //将数据元素e插入到线性表的i号位置
    public void add(int i,Object e);

    //将数据元素e插入到线性表末尾
    public void add(Object e);

    //将数据元素e插入到元素obj之前
    public boolean addBefore(Object obj,Object e);


    //将数据元素e插入到元素obj之后
    public boolean addAfter(Object obj,Object e);

    //删除线性表中序号为i的元素,并返回之
    public Object remove(int i);

    //删除线性表中第一个与e相同的元素
    public boolean remove(Object e);

    //替换线性表中序号为i的数据元素为e,返回原数据元素
    public Object replace(int i,Object e);

}

2. 创建类ArrayList实现自定义List接口

package com.cqc.ArrayList;

import java.util.Arrays;

/**
 * 顺序表,底层是数组,长度可以动态变化,使用扩容机制
 */
public class ArrayList implements List {


    private Object[] elementData; //根据java.util.ArrayList,底层使用数组,元素为Object类型,没有确定长度
    private int size; //不是数组长度,而是元素的个数,默认为0

    /**
     * 有参构造
     * @param initialCapacity 指定数组的初始长度
     */
    public ArrayList(int initialCapacity) {
        //给数组elementData分配空间
        elementData = new Object[initialCapacity];
    }

    /**
     * 无参构造方法,调用有参方法,指定数组长度
     */
    public ArrayList(){
        this(4); //指定默认长度为4
        //不指定长度,长度为0
//      elementData = new Object[]{};
    }



    @Override
    public int size() {
        //返回数组元素个数
        return size;
    }

    @Override
    public Object get(int i) {
        //按索引返回数组的元素
        return elementData[i];
    }

    @Override
    public boolean isEmpty() {

        //size为0,则为true
        return size==0;
    }

    @Override
    public boolean contains(Object e) {
        //若果这个对象的索引在这个数组内,索引不为-1
        return indexOf(e) >= 0;
    }

    @Override
    public int indexOf(Object e) {
        //分为null和非null两种处理方式
        if(e == null){
            //遍历查找第一个为null的index
            for(int i =0;i<size;i++){
                if(elementData[i] == null){
                    return i;
                }
            }
        }else {
            //查找第一个等于
            for(int i=0;i<size;i++){
                if(elementData[i] == e){
                    return i;
                }
            }
        }
        //若没有找到,返回-1
        return -1;
    }

    @Override
    public void add(int i, Object e) {

        //添加时先判断数组是否满了,如果满了,就扩容
        if(elementData.length == size){
            grow();
        }
        //后移索引i和后边的元素,从最后一个开始
        for(int j=size;j>i;j--){ //j表示的索引是现有最大索引+1
            elementData[j] = elementData[j-1];
        }
        //将要添加的元素加进去
        elementData[i] = e;
        size++;
    }

    /**
     * 添加元素,并完成扩容操作
     * @param e
     */
    @Override
    public void add(Object e) {
//        //添加时先判断数组是否满了,如果满了,就扩容
//        if(elementData.length == size){
//            grow();
//        }
//        //给数组最后一个元素后边添加新元素,数组元素个数+1
//        elementData[size++] = e;
        this.add(size,e);
    }

    //扩容,将数组长度扩容到原来的3/2
    private void grow(){

//            //新创建一个新的数组,长度为旧数组的2倍
//            Object[] newArray = new Object[elementData.length*2];
//            //将旧数组的数据copy到新数组
//            for(int i =0;i<size;i++){ //有size个数据
//                newArray[i] = elementData[i];
//            }
//            //让elementData指向新数组
//            elementData = newArray;

        //使用Arrays的工具类实现,指定扩容的数组,新长度,和返回的指向
        elementData = Arrays.copyOf(elementData, elementData.length+elementData.length/2);
    }

    @Override
    public boolean addBefore(Object obj, Object e) {
        //获取obj的索引
        int index = this.indexOf(obj);
        //若数组没有此元素,添加失败
        if(index == -1){
            return false;
        }
        //进行添加操作
        this.add(index,e);
        return true;
    }

    @Override
    public boolean addAfter(Object obj, Object e) {
        //获取obj的索引
        int index = this.indexOf(obj);
        //若数组没有此元素,添加失败
        if(index == -1){
            return false;
        }
        //进行添加操作
        this.add(index+1,e);
        return true;
    }

    @Override
    public Object remove(int i) {
        Object o = elementData[i];
        //将索引i后边的元素前移即可,最后一个元素的索引为size-1
        for(int j=i;j<size-1;j++){
            //若j+1为最后一个元素,应为size-1,j为size-2
            elementData[j] = elementData[j+1];
        }
        elementData[size-1] = null;
        //返回被移除的那个对象
        return o;
    }

    @Override
    public boolean remove(Object e) {
        //判断数组是否包含此元素
        if(contains(e)){
            //删除此元素
            remove(indexOf(e));
            return true;
        }
        return false;
    }

    /**
     * 替换元素,返回被替换的元素
     * @param i
     * @param e
     * @return
     */
    @Override
    public Object replace(int i, Object e) {
        Object o = elementData[i];
        elementData[i]= e;
        return o;
    }


    /**
     * 打印集合中的数字,格式[123,3213,2323]
     * @return
     */
    @Override
    public String toString() {

        if(size == 0){
            return "[]";
        }
        StringBuilder stringBuilder = new StringBuilder("["); //字符串开始符号为[
        for(int i = 0 ;i<size;i++){
            if(i !=size-1){
                stringBuilder.append(elementData[i]+",");
            }else {
                stringBuilder.append(elementData[i]);
            }
        }
        stringBuilder.append("]"); //字符串结尾符号
        return stringBuilder.toString();
    }
}

3. 重要的方法分析

3.1 两个重要的变量

在这里插入图片描述
Object[] elementData是ArrayList底层的一个数组,用来存放任意类型的元素.
size为数据中元素的个数.,根据其大小,可以判断数值是否为空,数组的元素个数.

3.2 构造方法

在这里插入图片描述
① 有参构造方法,给数组分配内存空间,初始值为参数的大小
② 无参构造方法:调用有参,默认分配大小为4,也可以指定为空

3.3 给底层数组扩容的方法grow()

在这里插入图片描述
使用Arrays工具类快捷扩容,java.util.ArrayList的扩容大小为原数组长度的3/2.
扩容步骤:new出新数组,把旧数组值拷贝到新数组,让旧数组的指针指向新数组

3.4 增加元素

首先判断数组是不是满了,满了就扩容,添加完元素,改变size大小
在这里插入图片描述

给指定位置增加元素:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值