数据结构——DIY简单的ArrayList

本文详细介绍了如何自定义实现一个动态数组类,包括构造函数、基本方法(如size、isEmpty、contains、get等)以及核心的add、remove方法。与Java内置的ArrayList进行对比,解释了实现细节和优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、简介

ArrayList是经典而又常用的数据结构,说白了就是非线程安全的动态数组,相比于数组长度不可改变的特点,ArrayList可以动态的增删数据而无需考虑数组大小,因为它的内部对数组的处理做了一些封装;

ArrayList实现机制,简单来说:内部维护了一个Array数组(elementData)保存数据,当长度不够时则创建一个更大的数组,并把原数组复制过去,并对其它的一些操作进行了很好的封装,下面就是我自己实现的一个简单的动态数组。


二、自己写一个简单的ArrayList

1. 初始化和构造函数

真正存储数据的数组 Object[] elements;

设置默认数组elements大小为8(源码为10)

数组最大容量为Integer.MAX_VALUE - 8,java虚拟机要保留有关信息在数组中,所以预留8个位置

提供两个构造方法,有参的设置大小,无参的调用有参的,设置数组大小为默认值

代码:

    /**
     * 默认数组大小
     */
    private static final int DEFAULT_SIZE = 8;

    /**
     * 数组最大容量,VM要保留数组头部信息在数组中,所以预留8个位置
     */
    private static final int MAX_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 数组大小
     */
    private int size;

    private Object[] elements;


    public YhArrayList() {
        this(DEFAULT_SIZE);
    }

    public YhArrayList(int size) {
        if (size < 0) {
            throw new IllegalArgumentException("不合法的初始化大小:" + size);
        } else {
            elements = new Object[size];
        }
    }

2. contains()、indexOf()、isEmpty()、get()等方法

代码:

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean contains(Object o) {
        return indexOf(o) != -1;
    }

    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++) {
                if (elements[i] == o) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < size; i++) {
                if (o.equals(elements[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 检查是否越界,越界则抛出异常
     * @param index
     */
    private void checkRange(int index) {
        if (index < 0 || index > MAX_SIZE) {
            throw new IndexOutOfBoundsException("数组越界:index == " + index);
        }
    }

    public Y get(int index) {
        checkRange(index);
        return (Y) elements[index];
    }

3.add()方法

核心是通过ensureCapacity(int size)方法保证size大小,其内部调用explicitCapacity(int size)实现自动扩容(1.5倍)。

代码:

ensureCapavity()和explicitCapacity():

 /**
     * 判断是否需要扩容
     * size>Integer.MAX_VALUE时变负,所以增加size<0的判断
     *
     * @param size
     */
    private void ensureCapacity(int size) {
        if (size > DEFAULT_SIZE) {
            explicitCapacity(size);
        }
        if (size < 0) {
            throw new IndexOutOfBoundsException("数组越界:size == " + size);
        }
    }

    /**
     * 真正实现扩容
     * 先扩容1.5倍,若还小于申请长度,则扩容为所申请的长度,若大于最大长度,则设为最大长度
     * 调用Arrays.copyOf()实现数组的复制,参数是被复制的数组和复制的长度,返回的是复制后的数组
     * (复制的长度大于被复制数组的长度,用类型的默认值填充)
     *
     * @param size
     */
    private void explicitCapacity(int size) {
        int oldCapacity = elements.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity < size) {
            newCapacity = size;
        }
        if (newCapacity > MAX_SIZE) {
            newCapacity = MAX_SIZE;
        }
        elements = Arrays.copyOf(elements, newCapacity);
    }

add()方法:

 public void add(Y y) {
        //扩容操作
        ensureCapacity(size + 1);
        //将对象添加到size位置,并将size+1
        elements[size++] = y;
    }

    public void add(int index, Y y) {
        //判断index是否越界
        checkRange(index);
        //保证大小(如果需要,自动扩容)
        ensureCapacity(size + 1);
        //将elements中从index往后的size-index个元素向后移一位(移动到elements的从index+1往后的size-index个位置中)
        System.arraycopy(elements, index, elements, index + 1, size - index);
    }

4. remove()方法

代码:

/**
     * 判断index后面元素个数,若大于0则将他们前移一位,将size减一,将原最后一位置空
     *
     * @param index
     * @return
     */
    public Y remove(int index) {
        Y y = get(index);
        int moveSize = size - index - 1;
        if (moveSize > 0) {
            System.arraycopy(elements, index + 1, elements, index, size - index - 1);
        }
        elements[--size] = null;
        return y;
    }

    /**
     * 配合contains()和remove()实现,返回值为是否删除成功
     * @param o
     * @return
     */
    public boolean remove(Object o) {
        if (contains(o)) {
            remove(indexOf(o));
            return true;
        } else {
            return false;
        }
    }

三、完整源码

package com.yh.datamaker.list;
import java.util.Arrays;

/**
 * @author: YH
 * @date: 2018/7/8 0008
 * @function 自己实现动态数组YhArrayList
 */
public class YhArrayList<Y> {

    /**
     * 默认数组大小
     */
    private static final int DEFAULT_SIZE = 8;

    /**
     * 数组最大容量,VM要保留数组头部信息在数组中,所以预留8个位置
     */
    private static final int MAX_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 数组大小
     */
    private int size;

    private Object[] elements;


    public YhArrayList() {
        this(DEFAULT_SIZE);
    }

    public YhArrayList(int size) {
        if (size < 0) {
            throw new IllegalArgumentException("不合法的初始化大小:" + size);
        } else {
            elements = new Object[size];
        }
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public boolean contains(Object o) {
        return indexOf(o) != -1;
    }

    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++) {
                if (elements[i] == o) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < size; i++) {
                if (o.equals(elements[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 检查是否越界,越界则抛出异常
     * @param index
     */
    private void checkRange(int index) {
        if (index < 0 || index > MAX_SIZE) {
            throw new IndexOutOfBoundsException("数组越界:index == " + index);
        }
    }

    public Y get(int index) {
        checkRange(index);
        return (Y) elements[index];
    }

    public void add(Y y) {
        //扩容操作
        ensureCapacity(size + 1);
        //将对象添加到size位置,并将size+1
        elements[size++] = y;
    }

    public void add(int index, Y y) {
        //判断index是否越界
        checkRange(index);
        //保证大小(如果需要,自动扩容)
        ensureCapacity(size + 1);
        //将elements中从index往后的size-index个元素向后移一位(移动到elements的从index+1往后的size-index个位置中)
        System.arraycopy(elements, index, elements, index + 1, size - index);
    }

    /**
     * 判断是否需要扩容
     * size>Integer.MAX_VALUE时变负,所以增加size<0的判断
     *
     * @param size
     */
    private void ensureCapacity(int size) {
        if (size > DEFAULT_SIZE) {
            explicitCapacity(size);
        }
        if (size < 0) {
            throw new IndexOutOfBoundsException("数组越界:size == " + size);
        }
    }

    /**
     * 真正实现扩容
     * 先扩容1.5倍,若还小于申请长度,则扩容为所申请的长度,若大于最大长度,则设为最大长度
     * 调用Arrays.copyOf()实现数组的复制,参数是被复制的数组和复制的长度,返回的是复制后的数组
     * (复制的长度大于被复制数组的长度,用类型的默认值填充)
     *
     * @param size
     */
    private void explicitCapacity(int size) {
        int oldCapacity = elements.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity < size) {
            newCapacity = size;
        }
        if (newCapacity > MAX_SIZE) {
            newCapacity = MAX_SIZE;
        }
        elements = Arrays.copyOf(elements, newCapacity);
    }

    /**
     * 判断index后面元素个数,若大于0则将他们前移一位,将size减一,将原最后一位置空
     *
     * @param index
     * @return
     */
    public Y remove(int index) {
        Y y = get(index);
        int moveSize = size - index - 1;
        if (moveSize > 0) {
            System.arraycopy(elements, index + 1, elements, index, size - index - 1);
        }
        elements[--size] = null;
        return y;
    }

    /**
     * 配合contains()和remove()实现,返回值为是否删除成功
     * @param o
     * @return
     */
    public boolean remove(Object o) {
        if (contains(o)) {
            remove(indexOf(o));
            return true;
        } else {
            return false;
        }
    }
}

GitHub 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值