ArrayList.add(int index, E e)的数组越界

本文深入解析了Java中ArrayList.add(int index,E element)方法的工作原理,包括其内部实现机制及可能出现的数组越界错误的原因。通过具体示例展示了如何正确使用该方法。

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

最近在编程时遇到的小问题,就是ArrayList.add(int index, E e)。调用此方法时报了数组越界。


凭借着经验我是这样想的,当我们执行new ArrayList()时,进程为我们新开辟了size为10的数据。既然已经分配了数组,我们当然可以指定一个元素的位置,即调用add(n, e),只要n < size就不会有问题。有点想当然了。


看看ArrayList的add(int index, E element)的实现,


 /**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

调用add后,会先执行rangeCheckForAdd方法,rangeCheckForAdd的实现如下:

 /**
     * A version of rangeCheck used by add and addAll.
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }


index会和ArrayList的私有变量size做比较,那问题就是size到底是多少?什么时候会被改写?


JDK1.6和JDK1.7的实现方式发生了变化,我们以1.7为例子,

添加元素成功后会执行size++,删除元素成功会执行size--。也就是说size是元素个数,并不是数组的长度。

当我们new ArrayList()时,默认给个空的数组,并未指定大小的数组。

 private static final Object[] EMPTY_ELEMENTDATA = {};

   /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

默认长度是10。


长话短说,

当我们调用add(int index, E e)时,index必须小于size。

            String case1 = "case1";
	    String case3 = "case3";
	    String case4 = "case4";
	    
	    List<String> list = new ArrayList<String>();
	    list.add(case1);
	    list.add(case3);
	    list.add(case4);
	    
	    String case2 = "case2";
	    list.add(n, case2);
	    System.out.println(list);


上面的例子,当n 小于3时才会执行成功,n > 3时就会报数组越界。



### 实现 ArrayList 并支持扩容/缩容功能 #### 概述 `ArrayList` 是一种基于连续内存区域的数据结构,类似于 C++ 中的 `std::vector` 或 Java 的 `ArrayList`。它的特点是能够动态调整大小以适应元素的变化需求。下面将详细介绍如何用 C 语言实现这一数据结构,并提供其核心功能。 --- ### **1. 功能设计** 我们需要实现以下内容: - **核心功能**:添加、删除、查找等基本操作。 - **动态调整容量**:通过 `resize()` 函数,在需要时自动扩增或缩减数组容量。 - **测试用例**:验证所有 API 是否正常工作。 以下是具体的文件划分: 1. **头文件 (`ArrayList.h`)** - 定义 `ArrayList` 数据结构及其相关接口函数原型。 2. **源文件 (`ArrayList.c`)** - 包含 `ArrayList` 的实现细节,包括初始化、插入、删除以及动态调整容量等功能。 3. **主程序文件 (`main.c`)** - 编写测试用例,对上述功能逐一验证。 --- ### **2. 文件实现** #### (1) ArrayList.h ```c #ifndef ARRAYLIST_H #define ARRAYLIST_H #include <stdbool.h> // 定义ArrayList结构体 typedef struct { int *data; // 存储数据的指针 size_t capacity;// 数组当前容量 size_t size; // 当前存储的有效元素个数 } ArrayList; // 初始化ArrayList void ArrayList_init(ArrayList *list); // 销毁ArrayList并释放资源 void ArrayList_destroy(ArrayList *list); // 添加元素到ArrayList末尾 bool ArrayList_add(ArrayList *list, int value); // 删除指定位置的元素 bool ArrayList_removeAt(ArrayList *list, size_t index); // 获取指定索引处的值 int ArrayList_get(ArrayList *list, size_t index); // 设置指定索引处的值 bool ArrayList_set(ArrayList *list, size_t index, int value); // 返回ArrayList中有效元素的数量 size_t ArrayList_size(ArrayList *list); // 调整ArrayList的容量(扩容/缩容) bool ArrayList_resize(ArrayList *list, size_t newCapacity); #endif /* ARRAYLIST_H */ ``` --- #### (2) ArrayList.c ```c #include "ArrayList.h" #include <stdlib.h> #include <stdio.h> // 初始默认容量 #define DEFAULT_CAPACITY 4 // 扩展系数(当容量不足时增加多少倍) #define RESIZE_FACTOR 2 // 改变ArrayList的容量 static bool resize(ArrayList *list, size_t newCapacity) { if (newCapacity == list->capacity || newCapacity == 0) return false; int *newData = realloc(list->data, sizeof(int) * newCapacity); if (!newData) return false; // 内存分配失败 list->data = newData; list->capacity = newCapacity; return true; } // 初始化ArrayList void ArrayList_init(ArrayList *list) { list->data = malloc(sizeof(int) * DEFAULT_CAPACITY); list->capacity = DEFAULT_CAPACITY; list->size = 0; } // 销毁ArrayList并释放资源 void ArrayList_destroy(ArrayList *list) { free(list->data); list->data = NULL; list->capacity = list->size = 0; } // 添加元素到ArrayList末尾 bool ArrayList_add(ArrayList *list, int value) { if (list->size >= list->capacity) { // 如果空间不够,则先扩充容量 if (!ArrayList_resize(list, list->capacity * RESIZE_FACTOR)) return false; } list->data[list->size++] = value; return true; } // 删除指定位置的元素 bool ArrayList_removeAt(ArrayList *list, size_t index) { if (index >= list->size || list->size == 0) return false; for (size_t i = index; i < list->size - 1; ++i) { list->data[i] = list->data[i + 1]; } --list->size; // 若剩余元素较少则缩小容量 if (list->size <= list->capacity / RESIZE_FACTOR && list->capacity > DEFAULT_CAPACITY) { ArrayList_resize(list, list->capacity / RESIZE_FACTOR); } return true; } // 获取指定索引处的值 int ArrayList_get(ArrayList *list, size_t index) { if (index >= list->size) return -1; // 索引越界返回错误码(-1) return list->data[index]; } // 设置指定索引处的值 bool ArrayList_set(ArrayList *list, size_t index, int value) { if (index >= list->size) return false; list->data[index] = value; return true; } // 返回ArrayList中有效元素的数量 size_t ArrayList_size(ArrayList *list) { return list->size; } // 公开调整容量的功能 bool ArrayList_resize(ArrayList *list, size_t newCapacity) { return resize(list, newCapacity); } ``` --- #### (3) main.c ```c #include "ArrayList.h" int main(void) { ArrayList list; ArrayList_init(&list); // 初始化ArrayList printf("初始状态:\n"); printf("Size=%zu, Capacity=%zu\n", ArrayList_size(&list), list.capacity); // 测试添加元素 for (int i = 0; i < 10; ++i) { ArrayList_add(&list, i * 10); } printf("\n添加10个元素后的状态(每步*10):\n"); for (size_t i = 0; i < ArrayList_size(&list); ++i) { printf("%d ", ArrayList_get(&list, i)); } printf("\nSize=%zu, Capacity=%zu\n", ArrayList_size(&list), list.capacity); // 测试获取和设置特定索引的值 printf("\n修改第5位的值为888:"); ArrayList_set(&list, 5, 888); for (size_t i = 0; i < ArrayList_size(&list); ++i) { printf("%d ", ArrayList_get(&list, i)); } // 测试删除中间元素 printf("\n删除第6位元素:"); ArrayList_removeAt(&list, 6); for (size_t i = 0; i < ArrayList_size(&list); ++i) { printf("%d ", ArrayList_get(&list, i)); } // 清理资源 ArrayList_destroy(&list); printf("\n清理完成.\n"); return 0; } ``` --- ### **运行结果示例** 假设我们按照上面代码执行,可能会得到类似的结果: ``` 初始状态: Size=0, Capacity=4 添加10个元素后的状态(每步*10): 0 10 20 30 40 50 60 70 80 90 Size=10, Capacity=16 修改第5位的值为888: 0 10 20 30 40 888 60 70 80 90 删除第6位元素: 0 10 20 30 40 888 70 80 90 清理完成. ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值