Java中的ArrayList:Java中最常用的动态数组,你了解多少?
《Java零基础教学》是一套深入浅出的 Java 编程入门教程。全套教程从Java基础语法开始,适合初学者快速入门,同时也从实例的角度进行了深入浅出的讲解,让初学者能够更好地理解Java编程思想和应用。
本教程内容包括数据类型与运算、流程控制、数组、函数、面向对象基础、字符串、集合、异常处理、IO 流及多线程等 Java 编程基础知识,并提供丰富的实例和练习,帮助读者巩固所学知识。本教程不仅适合初学者学习,也适合已经掌握一定 Java 基础的读者进行查漏补缺。
前言
在Java语言中,数组的大小是在创建时就已经确定的,而且一旦确定之后也不能再次改变。为了弥补这个不足,Java提供了ArrayList类,它封装了一个动态的可增长的对象数组。ArrayList比数组具有更大的灵活性和更方便的方法。本文将对ArrayList的原理与使用进行详细介绍。
摘要
本文将介绍以下内容:
- ArrayList是什么,它有哪些特点;
- ArrayList的源码实现与详细解析;
- ArrayList的常用方法介绍;
- ArrayList的测试用例;
- 全文小结。
ArrayList是什么?
ArrayList是Java中最常用的动态数组。它是List接口的一个实现,可以自动扩容,支持增删改查操作。与数组相比,ArrayList有以下几个优势:
- 可以自动扩容,动态添加元素;
- 方便进行元素的增删改查操作;
- 支持泛型,用于存储任意类型的对象。
ArrayList源码实现与详解
ArrayList结构
在Java中,ArrayList实际上是封装了一个数组。这个数组通过构造函数传入一个初始化的容量大小,可以随着元素的增加自动扩容。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
//默认初始化容量大小
private static final int DEFAULT_CAPACITY = 10;
//存储元素的数组
transient Object[] elementData;
//数组中元素个数
private int size;
//...
}
java.util.ArrayList
源码页截图如下:
ArrayList的扩容机制
ArrayList的扩容机制是在添加元素时才进行的。当ArrayList中的元素个数达到容量大小时,会自动扩容。实际上扩容的方法是通过创建一个新的数组,然后将原来的元素全部复制到新的数组中,最后将新的数组替代旧的数组。
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
//每次扩容为原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果扩容后的容量比Integer.MAX_VALUE还大,就使用最大值作为容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
java.util.ArrayList
扩容机制源码如下:
ArrayList的常用方法介绍
ArrayList类提供了丰富的方法,包括添加、删除、修改、查询等。下面是一些常用的方法介绍。
添加元素
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
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++;
}
删除元素
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
修改元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
查询元素
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
ArrayList的测试用例
如下我带着大家分别写个测试用例尝试一下,演示如下:
新增元素
//新增元素
@Test
public void testAdd() {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
System.out.println(list);
assertEquals(3, list.size());
}
测试用例执行如下:
删除元素
//删除元素
@Test
public void testRemove() {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
System.out.println("删除前:" + list);
list.remove("Python");
System.out.println("删除后:" + list);
assertEquals(2, list.size());
}
测试用例执行如下:
更新元素
//更新元素
@Test
public void testSet() {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
System.out.println("更新前:" + list);
list.set(1, "C++");
System.out.println("更新后:" + list);
assertEquals("C++", list.get(1));
}
测试用例执行如下:
根据下标查询元素
@Test
public void testGet() {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
assertEquals("Java", list.get(0));
assertEquals("Python", list.get(1));
}
测试用例执行如下:
根据元素查找下标
// 根据元素查找下标
@Test
public void testIndexOf() {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
System.out.println("list.indexOf(\"Java\") = " + list.indexOf("Java"));
System.out.println("list.indexOf(\"Python\") = " + list.indexOf("Python"));
assertEquals(0, list.indexOf("Java"));
assertEquals(1, list.indexOf("Python"));
}
测试用例执行如下:
全文小结
本文对ArrayList的定义、源码实现及常用方法进行了详细的介绍。通过本文的学习,我们可以清楚地了解ArrayList的结构,掌握它的扩容机制以及使用方法。ArrayList是Java中最常用的集合类之一,掌握好它的使用方法对于在Java开发中提高效率具有重要意义。
最后
大家如果觉得看了本文有帮助的话,麻烦给个三连(点赞、分享、转发)支持一下哈。
转载自:https://juejin.cn/post/7276630249546907687