玩转Java中的ArrayList:常用操作技巧和方法总结

玩转Java中的ArrayList:常用操作技巧和方法总结

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE相关知识点了,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~

代码语言:js复制环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8前言 在Java开发中,ArrayList是一种常见的数据结构。它可以动态地增加或删除元素,十分方便。但是,要想熟练掌握ArrayList的使用,不仅要了解常用的操作技巧和方法,还需要深入理解它的实现原理。本文就旨在帮助读者更好地掌握ArrayList,快速地进行开发。

摘要 本文首先介绍了ArrayList的定义和特点,然后详细描述了它的常用操作技巧和方法,包括添加元素、删除元素、遍历元素、查找元素等。接下来,通过源代码解析让读者了解ArrayList的底层实现原理,进一步理解它的性能和使用限制。进一步,本文通过应用场景案例分析,探讨ArrayList的使用场景和优缺点,以帮助读者在实际开发中更好地选择数据结构。最后,通过测试用例和全文小结,对本文内容进行总结,让读者更好地掌握ArrayList的使用方法和技巧。

ArrayList概述 ArrayList是Java中的一个类,它继承了AbstractList类,并且实现了List接口。它是一个动态数组,数组长度可以动态增加和缩小,它可以对数组中的元素进行增、删、改、查等操作。ArrayList可以存储任意类型的对象。

特点ArrayList的特点包括:

可变长度:ArrayList的长度是可变的,可以动态增加或缩小。重复元素:ArrayList中可以存储重复的元素。线程不安全:ArrayList不是线程安全的,如果有多个线程同时访问同一个ArrayList实例,可能会出现竞争条件。非同步:ArrayList不是同步的,不保证多个线程并发访问时的安全性。查找元素效率高:通过索引可以快速查找元素,时间复杂度为O(1)。源代码解析 ArrayList的底层实现是基于数组的,具体来说,它是通过一个Object类型的数组来存储元素的。在第一次添加元素时,会创建一个默认长度为10的数组,当数组空间不足时,会创建一个长度为原来数组长度+原来数组长度/2的新数组,并将原来数组中的元素复制到新数组中。在删除元素时,会将该元素后面的所有元素前移,如果删除的元素位于数组中间,则需要复制这两部分,同时更新数组长度。

ArrayList是Java集合框架中的一种数据结构,它基于数组实现,动态增长。下面是ArrayList的源代码解析:

类型参数定义:代码语言:java复制public class ArrayList extends AbstractList

implements List, RandomAccess, Cloneable, java.io.Serializable {

...

} 可以看到ArrayList实现了List接口、RandomAccess接口以及Cloneable接口,并且继承了AbstractList抽象类。其中,E表示ArrayList中的元素类型。

如下是部分源码截图:

成员变量定义:代码语言:java复制// 默认容量为10

private static final int DEFAULT_CAPACITY = 10;

// 所有元素

transient Object[] elementData;

// 数组实际数量

private int size;

// 可选的List迭代器

private static final class ListItr extends Itr implements ListIterator {

...

} elementData数组存放ArrayList中的所有元素,size记录了当前存放元素的数量。

构造函数定义:代码语言:java复制// 无参构造函数,初始化为默认容量10

public ArrayList() {

this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}

// 带初始容量参数的构造函数

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);

}

}

// 带集合参数的构造函数

public ArrayList(Collection c) {

elementData = c.toArray();

if ((size = elementData.length) != 0) {

if (elementData.getClass() != Object[].class)

elementData = Arrays.copyOf(elementData, size, Object[].class);

} else {

// 若集合为空,则初始化为默认容量

this.elementData = EMPTY_ELEMENTDATA;

}

} ArrayList支持无参、带初始容量参数、带集合参数的构造函数。其中,无参构造函数初始化为默认容量10,带初始容量参数的构造函数会检查参数是否合法,如果小于等于0则抛出IllegalArgumentException异常,带集合参数的构造函数会将集合转化为数组并存放在elementData数组中。

常用方法定义:代码语言:java复制// 添加元素,支持链式调用

public boolean add(E e) {

// 确保elementData数组可以存放新元素

ensureCapacityInternal(size + 1);

elementData[size++] = e;

return true;

}

// 获取指定下标的元素

@SuppressWarnings("unchecked")

public E get(int index) {

rangeCheck(index);

return (E) elementData[index];

}

// 删除指定下标的元素

public E remove(int index) {

rangeCheck(index);

modCount++;

E oldValue = elementData(index);

int numMoved = size - index - 1;

if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index,

numMoved);

elementData[--size] = null;

return oldValue;

}

// 获取元素数量

public int size() {

return size;

} 其中,ensureCapacityInternal方法用于确保elementData数组容量足够存放新元素,rangeCheck方法用于检查下标是否越界,modCount记录集合结构修改次数。

扩容机制 在添加元素时,如果elementData数组容量不足,则需要扩容。扩容过程如下:

代码语言:java复制private void grow(int minCapacity) {

// overflow-conscious code

int oldCapacity = elementData.length;

int newCapacity = oldCapacity + (oldCapacity >> 1);

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

// 将原数组元素拷贝到新数组

elementData = Arrays.copyOf(elementData, newCapacity);

}

private void ensureCapacityInternal(int minCapacity) {

ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));

}

private void ensureExplicitCapacity(int minCapacity) {

modCount++;

// overflow-conscious code

if (minCapacity - elementData.length > 0)

grow(minCapacity);

}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

private static int hugeCapacity(int minCapacity) {

if (minCapacity < 0) // overflow

throw new OutOfMemoryError();

return (minCapacity > MAX_ARRAY_SIZE) ?

Integer.MAX_VALUE :

MAX_ARRAY_SIZE;

}

private static int calculateCapacity(Object[] elementData, int minCapacity) {

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

return Math.max(DEFAULT_CAPACITY, minCapacity);

}

return minCapacity;

} grow方法用于扩容,将原数组容量增加一半并重新分配大小,如果新容量小于minCapacity,则将minCapacity赋值给新容量。如果新容量大于MAX_ARRAY_SIZE,则将新容量赋值为MAX_ARRAY_SIZE。然后将原数组元素拷贝到新数组中。ensureCapacityInternal方法用于确保elementData数组容量足够存放新元素。ensureExplicitCapacity方法用于确保elementData数组容量不小于minCapacity。calculateCapacity方法计算出需要的最小容量,如果elementData数组为空,则返回默认容量DEFAULT_CAPACITY和minCapacity中的较大值。

常用操作技巧和方法添加元素 在ArrayList中添加元素最基本的方法就是add()方法,该方法有两种重载形式,一种是无参的add()方法,一种是有参数的add(int index, E element)方法。无参的add()方法会在ArrayList的最后一位添加一个元素,而有参数的add(int index, E element)方法则可以将元素插入到指定的索引位置。

代码语言:java复制public boolean add(E e)

public void add(int index, E element) 如下是部分源码截图:

删除元素 在ArrayList中删除元素最常用的方法是remove()方法,该方法也有两种重载形式,一种是删除指定索引位置的元素,另一种是删除指定元素。需要注意的是,如果是使用remove(int index)方法删除元素,则会将该位置后面的所有元素向前移动一位,而如果是使用remove(Object o)方法,则会将第一个匹配到的元素删除。

代码语言:java复制public E remove(int index)

public boolean remove(Object o)遍历元素在ArrayList中遍历元素可以使用for循环和foreach语句,如下所示:

代码语言:java复制package com.example.javase.se.classes;

import java.util.ArrayList;

/**

* @Author ms

* @Date 2023-11-02 19:13

*/

public class ArrayListTest {

public static void main(String[] args) {

ArrayList list = new ArrayList();

list.add("Java");

list.add("Python");

list.add("C++");

// 使用for循环遍历元素

for (int i = 0; i < list.size(); i++) {

String element = list.get(i);

System.out.println(element);

}

// 使用foreach语句遍历元素

for (String element : list) {

System.out.println(element);

}

}

}测试结果 根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。

查找元素 在ArrayList中查找元素可以使用indexOf()方法或contains()方法。其中,indexOf()方法返回该元素第一次出现的位置的索引值,如果没有找到该元素,则返回-1;contains()方法返回ArrayList中是否存在该元素,返回值为布尔型。

代码语言:java复制public int indexOf(Object o)

public boolean contains(Object o)应用场景案例场景一:存储简单数据类型 在Java中,数组是一种非常基本的数据结构,可以用来存储简单数据类型,例如int、double、boolean等。但是,数组的长度是不可变的,如果需要动态增加或删除元素,就需要使用ArrayList。例如:

代码语言:java复制ArrayList list = new ArrayList();

list.add(1);

list.add(2);

list.add(3);场景二:实现栈和队列 栈和队列是计算机科学中常见的数据结构。栈是一种LIFO(Last-In-First-Out)的数据结构,队列是一种FIFO(First-In-First-Out)的数据结构。借助ArrayList可以很容易地实现栈和队列。例如:

代码语言:java复制// 实现栈

ArrayList stack = new ArrayList();

stack.add(1);

stack.add(2);

stack.add(3);

Integer top = stack.remove(stack.size() - 1);

// 实现队列

ArrayList queue = new ArrayList();

queue.add(1);

queue.add(2);

queue.add(3);

Integer front = queue.remove(0);优缺点分析ArrayList的优点包括:

索引快速查找:通过索引可以快速查找元素,时间复杂度为O(1)。可变长度:ArrayList的长度是可变的,可以动态增加或缩小。可存储任意类型的对象:ArrayList可以存储任意类型的对象,灵活性高。ArrayList的缺点包括:

不适合大量元素的添加和删除:由于ArrayList底层是基于数组实现的,因此在进行大量元素的添加或删除时,会存在数组复制的问题,影响性能。线程不安全:ArrayList不是线程安全的,如果有多个线程同时访问同一个ArrayList实例,可能会出现竞争条件。非同步:ArrayList不是同步的,不保证多个线程并发访问时的安全性。类代码方法介绍 在Java中,ArrayList是一个类,我们可以自己创建ArrayList对象并进行操作。ArrayList中的常用方法已经在前面进行了介绍,这里就不再赘述,但是需要注意的是,ArrayList继承了AbstractList类,并且实现了List接口,因此,它还有一些其他的方法,例如:

代码语言:java复制public boolean isEmpty()

public void clear()

public boolean equals(Object o)

public Object[] toArray()测试用例 在本文中,我们介绍了ArrayList的定义和特点,详细描述了它的常用操作技巧和方法,通过源代码解析让读者了解ArrayList的底层实现原理,通过应用场景案例分析,探讨ArrayList的使用场景和优缺点,以帮助读者在实际开发中更好地选择数据结构。下面,我们构建一个测试用例来检验ArrayList的操作是否正确:

代码语言:java复制package com.demo.javase.day58;

import java.util.ArrayList;

/**

* @Author bug菌

* @Date 2023-11-05 23:45

*/

public class ArrayListTest {

public static void main(String[] args) {

// 创建一个空的ArrayList对象

ArrayList list = new ArrayList();

// 添加元素

list.add("Java");

list.add("Python");

list.add("C++");

// 遍历元素

for (String element : list) {

System.out.println(element);

}

// 插入元素

list.add(1, "JavaScript");

// 删除元素

list.remove("C++");

// 查找元素

boolean contains = list.contains("Java");

int index = list.indexOf("Python");

// 输出结果

System.out.println(list);

System.out.println("List contains Java? " + contains);

System.out.println("Index of Python: " + index);

}

}运行结果如下所示:

代码语言:java复制Java

Python

C++

[Java, JavaScript, Python]

List contains Java? true

Index of Python: 2测试结果 根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。

测试用例中,我们创建了一个空的ArrayList对象,并向其中添加了三个元素。接着,我们使用for-each语句遍历ArrayList中的所有元素,然后插入了一个新元素,并删除了一个元素。最后,我们使用contains()方法和indexOf()方法查找元素,并输出结果。可以看到,ArrayList的操作均正确无误。

测试代码分析 根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。

这是一个用于演示 ArrayList 使用的 Java 类,主要实现了以下功能:

创建一个空的 ArrayList 对象;向 ArrayList 中添加元素;遍历 ArrayList 中的元素;插入元素到指定位置;删除元素;查找元素在 ArrayList 中的位置。 在 main 方法中,创建了一个空的 ArrayList 对象 list,并向其中添加了三个元素:Java、Python 和 C++。接着使用 for 循环遍历了 list 中的元素,并对每个元素进行了输出。然后调用了 list.add(1, "JavaScript") 方法,在 list 中第二个位置插入了一个元素 JavaScript。接着又调用了 list.remove("C++") 方法,将 list 中的 C++ 元素删除。最后通过 list.contains("Java") 方法查找元素 Java 是否在 list 中,并使用 list.indexOf("Python") 方法查找元素 Python 在 list 中的位置,将查找结果输出。

总体来说,这个类演示了 ArrayList 的基本使用方法,包括添加、删除、插入和查找元素等。

总结 本文详细介绍了Java中的ArrayList类,包括其定义和特点、常用操作技巧和方法、源代码解析、应用场景案例分析以及优缺点分析等方面。文章通过测试用例对ArrayList的操作进行了验证,并给读者提供了一些学习建议和推荐。通过本文的学习,读者可以更好地掌握ArrayList的使用方法和技巧,快速地进行开发。

...

好啦,这期的内容就基本接近尾声啦,若你想学习更多,可以参考这篇专栏总结《「滚雪球学Java」教程导航帖》,本专栏致力打造最硬核 Java 零基础系列学习内容,🚀打造全网精品硬核专栏,带你直线超车;欢迎大家订阅持续学习。

附录源码 如上涉及所有源码均已上传同步在「Gitee」,提供给同学们一对一参考学习,辅助你更迅速的掌握。

☀️建议/推荐你 无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学Java」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门Java编程,就像滚雪球一样,越滚越大,指数级提升。

最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。

📣关于我 我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。

--End

我正在参与我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

🎨 相关创意作品

深度评测(揭秘K1的音质表现、舒适度和智能功能,为你带来绝佳音乐体验!)
苹果电脑为什么要换 CPU:Intel 与 ARM 的战争
365bet怎么设置中文

苹果电脑为什么要换 CPU:Intel 与 ARM 的战争

📅 06-30 👁️ 1115
洛克王国世界皇家狮鹫怎么获得,强度怎么样,一篇文章告诉你!