今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
在Java开发中,我们经常需要使用集合类来存储和操作数据。而ArrayList类是Java中最常用的集合类之一。本文将对ArrayList类进行详细讲解,帮助读者更好地了解并应用ArrayList类。
摘要
本文将介绍Java中的ArrayList类,包括其基本概念、实现原理和应用场景,同时对ArrayList类的优缺点进行分析,最后提供ArrayList类的类代码方法介绍和测试用例,以及全文小结和总结。
ArrayList类
简介
ArrayList是Java语言中的一个集合类,属于Java Collections Framework中的List接口的实现类。与数组相比,ArrayList类具有动态扩容、插入和删除元素方便等优点。ArrayList类底层是使用数组来实现的,因此其性能与数组相当。
源代码解析
- ArrayList类的定义
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
//...
}
从上面的代码可以看出,ArrayList类实现了List接口和RandomAccess接口,同时继承了AbstractList类,实现了Cloneable和Serializable接口。
如下是部分源码截图:
- 动态扩容实现
在ArrayList类中,需要使用数组来存储数据,但是数组创建时需要指定长度,因此无法支持动态扩容。为了解决这个问题,ArrayList类将数组的容量设置为默认值10。当数据存储空间不足时,ArrayList类会通过grow方法动态调整数组长度。
private void grow(int minCapacity) {
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);
}
在上述代码中,grow方法会根据当前数组长度计算出新的数组长度,然后调用Arrays.copyOf方法将原数组中的元素复制到新数组中。需要注意的是,新数组长度不能超过MAX_ARRAY_SIZE,否则会抛出OutofMemoryError异常。
如下是部分源码截图:
- 插入和删除元素实现
对于插入和删除元素操作,ArrayList类提供了add和remove方法。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 是否需要扩容
elementData[size++] = e;
return true;
}
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;
}
在上述代码中,add方法中的ensureCapacityInternal方法判断当前数组长度是否满足需求,如果数组空间不足,则会调用grow方法对数组进行扩容。然后将新元素添加到数组末尾。remove方法中会先检查下标是否合法,然后将待删除元素后面的元素依次向前移动一位,然后将最后一个元素位置清空。
应用场景案例
ArrayList类适用于存储数量不确定的数据,并且需要随时对数据进行插入和删除操作的场景。例如,需要存储动态数据集合或读取数据文件时,ArrayList都是很好的选择。
优缺点分析
优点
- 支持动态扩容,可以动态增加存储空间。
- 插入和删除元素方便,不需要自行维护数组下标。
- 可以存储任意类型的数据,具有泛型特性。
- 支持快速随机访问元素。
缺点
- 数组默认长度为10,如果预估数量过多,需要手动调用ensureCapacity方法进行扩容,否则可能会发生内存溢出。
- 插入和删除元素时,需要将元素后面的元素全部向前或向后移动,性能会受到影响。
类代码方法介绍
构造方法
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<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
增加元素方法
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // 是否需要扩容
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
拓展:
如上是 Java 中 ArrayList 类的 add 方法的两个重载版本。
第一个方法 add(E e)
是在列表末尾添加元素,它首先会调用 ensureCapacityInternal
方法来确保内部数组 elementData
的容量足够存放新的元素。如果容量不够,则进行扩容操作。然后将元素添加到数组的末尾,最后返回 true
。
第二个方法 add(int index, E element)
是在指定位置添加元素,它首先会调用 rangeCheckForAdd
方法来检查指定的位置是否越界。然后调用 ensureCapacityInternal
方法确保数组容量足够,接着使用 System.arraycopy
方法将指定位置及其后面的元素向后移动一个位置。最后在指定位置插入新元素,更新列表的大小。
删除元素方法
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;
}
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; // clear to let GC do its work
return oldValue;
}
拓展:
这段代码是ArrayList类中的remove方法,可以用来从列表中删除指定对象或指定索引位置的元素。下面对代码进行分析:
- remove(Object o)方法:
- 如果要删除的对象o为null,则使用for循环遍历整个列表,如果找到了值为null的元素,则调用fastRemove方法快速删除该元素,并返回true;否则返回false。
- 如果要删除的对象o不为null,则使用for循环遍历整个列表,如果找到了与o相等的元素,则调用fastRemove方法快速删除该元素,并返回true;否则返回false。
- remove(int index)方法:
- 首先使用rangeCheck方法检查索引index是否有效,如果无效则抛出IndexOutOfBoundsException异常。
- 然后对modCount进行自增操作,表示列表结构已经发生了变化。
- 接着获取索引位置为index的元素的值oldValue。
- 如果要删除的元素不在列表末尾,则使用System.arraycopy方法将该元素后面的所有元素向前移动一位,从而删除该元素。
- 最后将列表的长度减1,并将最后一个元素设为null,以便让垃圾回收机制处理该元素。
总体来说,这段代码的实现比较简单,其中重点在于快速删除元素的实现,即fastRemove方法。
元素查找方法
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;
}
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
拓展:
上述代码中,定义了一个名为indexOf的方法,该方法返回对象o在数组elementData中第一次出现的索引位置,如果数组中不包含该对象,则返回-1。如果o为null,则遍历数组并查找为空的元素,若找到,则返回其索引位置。如果o不为null,则遍历数组并使用equals方法比较元素,若找到相等的元素,则返回其索引位置。
同时,该代码还定义了一个名为contains的方法,该方法调用indexOf方法来判断数组中是否包含对象o,并返回一个布尔值。如果返回值大于等于0,则表示数组中包含该对象,返回true;否则,返回false。
测试用例
测试代码演示
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<String> list = new ArrayList<>();
// Test add
list.add("Hello");
list.add("World");
list.add("Java");
System.out.println(list.get(0)); // Output: Hello
System.out.println(list.get(1)); // Output: World
System.out.println(list.get(2)); // Output: Java
// Test remove
list.remove(2);
System.out.println(list.contains("Java")); // Output: false
// Test indexOf
System.out.println(list.indexOf("World")); // Output: 1
}
}
测试结果
根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。
测试代码分析
根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。
该代码定义了一个名为ArrayListTest
的类,用于测试ArrayList的基本操作。在主方法中,首先创建了一个ArrayList<String>
对象,并用add()方法添加了三个字符串元素:“Hello”、“World"和"Java”。
然后又测试了remove()
方法,将索引为2的元素(即"Java")从集合中移除,并使用contains()
方法验证该元素是否存在,输出结果为false。
最后,测试了indexOf()
方法,查找"World"在集合中的索引位置,输出结果为1。
小结
- ArrayList是Java中最常用的集合类之一,底层是由数组实现的。
- ArrayList支持动态扩容,插入和删除元素方便,可以存储任何类型的数据。
- ArrayList的优点是支持动态扩容,插入和删除元素方便,可以存储任何类型的数据,同时支持快速访问元素。
- ArrayList的缺点是默认长度为10,如果预估数量过多,需要手动扩容,扩容时需要移动数据,性能受到影响。
总结
本文对Java中的ArrayList
类进行了详细介绍,包括其定义、实现原理、应用场景、优缺点分析、常用方法等。ArrayList
类是Java中最常用的集合类之一,它具有动态扩容功能和插入、删除元素方便等优点,适用于存储数量不确定的数据,并需要随时对数据进行插入和删除操作的场景。需要注意的是,在使用ArrayList类时需要注意预估存储数据的数量,并在必要时手动调用ensureCapacity
方法进行扩容,否则可能会发生内存溢出。
本文还提供了ArrayList类的构造方法、增加元素方法、删除元素方法和元素查找方法等代码实现,并提供了测试用例帮助读者更好地了解和应用ArrayList类。
最后,希望通过本文的介绍,读者对ArrayList类有更深入的了解,并能在实际开发中充分利用其优点,避免其缺点,提高程序的性能和效率。
… …
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
… …
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。