记录一次执行ArrayList的add方法异常细节复盘| Java Debug 笔记

简介: 记录一次执行ArrayList的add方法异常细节复盘| Java Debug 笔记

前言

看到这个问题的时候,一眼看去,这么简单的问题,为何会问。其实,转眼一想,是的,这个还是很具有迷惑性的问题。对于初学者,来说,这块确实容易迷失。很多人不理解。

那么,我们就来看看这个问题,对它进行一次深入的解剖!

问题复现

定义一个初始化大小为10的集合

ArrayList<Integer> arr=new ArrayList<Integer>(10);

使用集合方法进行添加元素

arr.add(5,10)

我们看一下结果

网络异常,图片无法展示
|

迷惑的地方出现了,为啥会报越界呢?我们明明已经初始化了集合的大小为10,add方法,添加的索引为5,还不到10。

估计初学者已经懵逼,我们就来详细看看咋回事。

问题解析

首先,我们来看集合的add方法,是怎么定义的

/**
 * 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++;
}

方法,确实提供了两个参数,索引位置,元素值。

通过了解注释,我们可以看到,将指定的元素插入此列表中的指定位置。 将当前在该位置的元素(如果有)和任何后续元素右移(将其索引添加一个)

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

观察方法rangeCheckForAdd

我们,可以了解到,该方法,判断的是index和size的比较

/**
 * The size of the ArrayList (the number of elements it contains).
 *
 * @serial
 */
private int size;

那么,我们看到之前异常截图,显示Size为0,这是为啥来,我们好像已经初始化了大小。

看来,问题,在于初始化。我们就来看看,我们自定义集合时,到底干了点什么。

/**
 * Constructs an empty list with the specified initial capacity.
 *
 * @param  initialCapacity  the initial capacity of the list
 * @throws IllegalArgumentException if the specified initial capacity
 *         is negative
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

我们发现,初始化时,指定的是initialCapacity 初始化容量大小,看出来,并不是size大小。

问题明朗了,我们混淆了Size和Capacity的概念。

问题总结

size 是集合包含元素的数量

capacity 是定义集合能够包含元素的数量

初学者,需要更细心的观察源码的实现。


目录
相关文章
|
15天前
|
Java
Java基础—笔记—static篇
`static`关键字用于声明静态变量和方法,在类加载时初始化,只有一份共享内存。静态变量可通过类名或对象访问,但推荐使用类名。静态方法无`this`,不能访问实例成员,常用于工具类。静态代码块在类加载时执行一次,用于初始化静态成员。
10 0
|
15天前
|
Java API 索引
Java基础—笔记—String篇
本文介绍了Java中的`String`类、包的管理和API文档的使用。包用于分类管理Java程序,同包下类无需导包,不同包需导入。使用API时,可按类名搜索、查看包、介绍、构造器和方法。方法命名能暗示其功能,注意参数和返回值。`String`创建有两种方式:双引号创建(常量池,共享)和构造器`new`(每次新建对象)。此外,列举了`String`的常用方法,如`length()`、`charAt()`、`equals()`、`substring()`等。
15 0
|
1天前
|
Java
[Java 面试题] ArrayList篇
[Java 面试题] ArrayList篇
|
1天前
|
存储 Java 程序员
JavaSE&Java的异常
JavaSE&Java的异常
|
15天前
|
Java API
Java基础—笔记—内部类、枚举、泛型篇
本文介绍了Java编程中的内部类、枚举和泛型概念。匿名内部类用于简化类的创建,常作为方法参数,其原理是生成一个隐含的子类。枚举用于表示有限的固定数量的值,常用于系统配置或switch语句中。泛型则用来在编译时增强类型安全性,接收特定数据类型,包括泛型类、泛型接口和泛型方法。
9 0
|
17天前
|
Java
Java中的异常类总结
Java中的异常类总结
|
1月前
|
SQL Java
java中的异常
java中的异常
10 1
|
1月前
|
Java 程序员 编译器
Java中异常
Java中异常
12 0
|
1月前
|
Java 程序员 编译器
Java中的异常
Java中的异常
9 0
|
1月前
|
Java
Java异常的抛出
Java异常的抛出
8 0