动态数组及泛型

动态数组

固定数组存在长度一旦初始化就无法修改的缺陷,新增、插入元素会受容量限制,因此需要手动封装动态数组,基于原生定长数组实现自动扩容、增删改查功能。

动态数组的方法
  • 末尾添加数据:数组长度 + 1,原数组全部元素复制,末尾存放新数据
  • 指定位置插入:插入位置前元素不变,插入位置存放新元素,后面元素统一后移一位
  • 删除指定位置数据:删除位置之后的元素统一向前覆盖一位,数组长度 - 1
  • 删除指定数据(使用布尔类型):遍历找到第一个匹配下标,调用按下标删除方法
  • 删除所有相同数据:循环执行单次数据删除,直到不存在目标元素

example
自定义动态数组 ArrList 完整实现代码

package com.yw.oop0627;

/**
 * @author YAN
 * @date 2026/6/27 17:36
 * @description 动态数组
 */
public class ArrList {
    //初始数组
    private int [] arr = new int[0];

    //末尾添加数据
    public void add(int data){
        //扩容原数组
        int [] nArr = new int [arr.length+1];
        nArr[arr.length] = data;
        //拷贝原数组数据到新数组
        for(int i = 0; i < arr.length; i++){
            nArr[i] = arr[i];
        }
        //更新对象头
        arr = nArr;
    }
    //插入数据
    public void insert(int index, int data){
        int [] newArr = new int [arr.length+1];
        //复制插入位置之前的数据
        for(int i = 0; i < index; i++){
            newArr[i] = arr[i];
        }
        //插入目标数据
        newArr[index] = data;
        //复制插入位置之后的数据
        for(int i = index; i < arr.length; i++){
            newArr[i + 1] = arr[i];
        }
        arr = newArr;
    }
    //删除指定位置数据,返回被删除的数据
    public int remove(int index){
        //保存要删除的元素
        int delNum = arr[index];
        int[] newArr = new int[arr.length - 1];
        //复制删除位置前数据
        for (int i = 0; i < index; i++) {
            newArr[i] = arr[i];
        }
        //删除位置后数据向前移动
        for (int i = index; i < newArr.length; i++) {
            newArr[i] = arr[i + 1];
        }
        arr = newArr;
        return delNum;
    }
    //删除指定数据(使用布尔类型)
    public boolean removes(int data){
        for (int i = 0; i < arr.length; i++) {
            if(arr[i] == data){
                remove(i);
                return true;
            }
        }
        return false;
    }
    //删除所有相同数据
    public boolean removeAll(int data){
        boolean flag = false;
        //循环删除,直到没有目标数据
        while(removes(data)){
            flag = true;
        }
        return false;
    }
    //获取数据
    public int get(int index){
        //判断index是否合法
        return arr[index];
    }
    //长度
    public int size(){
        return arr.length;
    }
    public static void main(String[] args){
        //测试
        ArrList list = new ArrList();
        list.add(1);
        list.add(2);
        list.add(3);
        for(int i = 0; i < list.size(); i++){
            System.out.print(list.get(i) + " ");
        }
        System.out.println("\n插入元素5到下标1位置:");
        list.insert(1,5);
        for(int i=0;i<list.size();i++){
            System.out.print(list.get(i)+" ");
        }

        System.out.println("\n删除下标2位置元素:"+list.remove(2));
        for(int i=0;i<list.size();i++){
            System.out.print(list.get(i)+" ");
        }
    }
}
动态数组的局限性

由于底层依然使用固定长度的 int 数组存储数据,因此只能添加整形数据,怎么怎么优化动态数组,让其能添加任何类型?
可使用object的数组
局限性:不同类型数据都混在一起
解决:使用泛型
规避耗时问题:减少拷贝次数,对原数组进行2倍扩容

example

package com.yw.oop0702;

/**
 * @author YAN
 * @date 2026/7/2 18:50
 * @description
 */
public class ArrList<E> {
    //初始数组
    private Object[] arr;
    private static int len = 10;  //动态数组的默认初始长度
    private int size = 0;   //记录有效数据个数

    //构造方法初始化数组长度
    public ArrList(int len){
        arr = new Object[len];
    }
    //设置长度
    public ArrList(){
        //构造方法相互调用:this(参数,,);
        this(len);
    }
    //末尾添加数据
    public void add(E e){
        //判断是否需要扩容
        if(size == arr.length){
            //对原数组2倍扩容
            Object[] nArr = new Object[arr.length*2];
            //拷贝愿数组数据到新数组
            for(int i=0;i<arr.length;i++){
                nArr[i] = arr[i];
            }
            //更新对象头
            arr = nArr;
        }
        arr[size] = e;
        size++;
    }
    //插入数据
    public void insert(int index,E e){
        //优先扩容
        if (size == arr.length) {
            Object[] nArr = new Object[arr.length*2];
            //拷贝愿数组数据到新数组
            for(int i=0;i<arr.length;i++){
                nArr[i] = arr[i];
            }
            //更新对象头
            arr = nArr;
        }
        //后移元素
        for (int i = size; i > index; i--) {
            arr[i] = arr[i - 1];
        }
        arr[index] = e;
        size++;
    }

    //删除指定位置数据,返回被删除的数据
    public E remove(int index){
        //把要删除位置的元素提前存起来
        E deleteElement = (E) arr[index]; //使用当前的泛型符号
        //元素前移覆盖
        for (int i = index; i < size - 1; i++) {
            arr[i] = arr[i + 1];
        }
        //最后的位置为空
        arr[size - 1] = null;
        //有效元素个数-1
        size--;
        //返回最开始保存的、被删除的元素
        return deleteElement;
    }
    //删除指定数据
    public boolean removes(E e){
        for (int i = 0;i < size; i++) {
            if (arr[i].equals(e)) {
                remove(i);
                return true;
            }
        }
        return false;
    }
    //删除所有相同
    public boolean removeAll(E e){
        for (int i = size - 1; i >= 0; i--) {
            if (arr[i].equals(e)) {
                remove(i);
                return true;
            }
        }
        return false;
    }
    //获取数据
    public E get(int index){
        //判断index是否合法
        return (E)arr[index];
    }
    //长度
    public int size(){
        return size;
    }

    public static void main(String[] args) {
        //测试
        ArrList<Integer> list = new ArrList<>();

        long start = System.currentTimeMillis();
        for(int i=0;i<100000;i++){
            list.add(i);
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start));
        //测试插入
        list.insert(0, 999);
        //测试删除
        list.remove(0);
        //测试删除指定元素
        list.removes(50000);
        System.out.println("当前有效元素个数:" + list.size());
    }

}

关于基本类型的对应包装类

基本数据类型 -> 包装类(java.lang 包下)
byte -> Byte
short -> Short
int -> Integer
long -> Long
float -> Float
double -> Double
char -> Character
boolean -> Boolean

关于Java内置动态数组ArrayList扩容机制
  1. 底层原理
    ArrayList 底层基于 Object [] 数组实现,属于动态数组。
// 默认初始容量:10
private static final int DEFAULT_CAPACITY = 10;
// 空数组常量(懒加载:无参构造初始化时不创建长度为10的数组,先赋值空数组,第一次add才初始化容量10)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 底层存储数组
transient Object[] elementData;
// 集合中实际存储的有效元素个数
private int size;
  1. 三种构造方法
  • 无参构造
public ArrayList() {
    // 初始化空数组,懒加载,首次添加元素才扩容到10
    elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
  • 指定初始容量构造
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    }
}
  • 集合参数构造:把其他集合转为 ArrayList
泛型<>

作用:把添加的数据形参化,限制相同类型的数据才能被添加到同一个集合对象
注:确定泛型的数据类型时必须是引用类型
常用泛型符号:
E T K V…(任意大写字母即可,E更为常用)

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐