赞
踩
Java ArrayList 是 Java 标准库中的一个重要类,它属于 Java 集合框架的一部分,用于存储和操作元素的动态数组。
ArrayList 是 Java 1.2 版本引入的,它提供了一种动态数组的实现方式,可以根据需要自动扩展数组的大小。
ArrayList 的特点:
1.导入 ArrayList 类:
在 Java 中,ArrayList 位于 java.util
包中,因此首先需要导入它。可以在代码的顶部添加以下导入语句:
import java.util.ArrayList;
2.声明 ArrayList 变量:
声明一个变量来保存 ArrayList 的引用。这是一个引用类型的变量,它将指向分配给它的 ArrayList 对象。例如:
ArrayList<String> myArrayList;
这里我们声明了一个名为 myArrayList
的 ArrayList 变量,它将存储字符串类型的元素。
3.初始化 ArrayList:
有几种方式可以初始化 ArrayList:
使用无参构造函数:
您可以使用无参构造函数创建一个空的 ArrayList:
myArrayList = new ArrayList<String>();
使用带初始容量的构造函数:
如果您知道大致需要多少元素,您可以在初始化时指定初始容量,以避免不必要的自动扩展:
myArrayList = new ArrayList<String>(10); // 初始化容量为10
使用集合初始化:
您还可以使用集合初始化语法来初始化 ArrayList,将一组元素添加到 ArrayList 中:
ArrayList<String> myArrayList = new ArrayList<>(Arrays.asList("元素1", "元素2", "元素3"));
从现有集合或另一个 ArrayList 初始化:
如果您有一个已经存在的集合或 ArrayList,您可以将它们传递给 ArrayList 构造函数来创建一个新的 ArrayList,包含现有集合的元素。
ArrayList<String> existingList = new ArrayList<>();
ArrayList<String> myArrayList = new ArrayList<>(existingList);
boolean add(E e)
将指定的元素追加到此列表的末尾。
void add(int index,E element)
在此列表中的指定位置插入指定的元素。
boolean addAll(Collection<? extends E> c)
按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。
boolean addAll(int index, Collection<? extends E> c)
将指定集合中的所有元素插入到此列表中,从指定的位置开始。
List<String> list = new ArrayList<>(); // add(E e) list.add("a"); list.add("c"); // add(int index,E element) list.add(1,"b"); list.forEach(s -> System.out.println(s)); // a b c List<String> list1 = new ArrayList<>(); list1.add("d"); // addAll(Collection<? extends E> c) list1.addAll(list); list1.forEach(s-> System.out.println(s));// d a b c // addAll(int index, Collection<? extends E> c) list1.addAll(0,list); list1.forEach(s-> System.out.println(s));// a b c d a b c
void clear()
从列表中删除所有元素。
E remove(int index)
删除该列表中指定位置的元素并返回。
boolean remove(Object o)
从列表中删除指定元素的第一个出现(如果存在)。
boolean removeAll(Collection<?> c)
从此列表中删除指定集合中包含的所有元素。
boolean removeIf(Predicate<? super E> filter)
删除满足给定谓词的此集合的所有元素。
list // a b c
list1 // a b c d a b c
// clear()
list1.clear();
list1.forEach(s-> System.out.println(s));// 无输出
// remove(int index)
System.out.println(list1.remove(1));// b
// remove(Object o)
list1.remove("a");
list1.forEach(s-> System.out.println(s));// b c d a b c
//removeAll(Collection<?> c)
list1.removeAll(list);
list1.forEach(s-> System.out.println(s));// d
removeIf(Predicate<? super E> filter)
用于根据指定的条件(谓词或 Predicate)删除集合中的元素。这个方法是在 Java 8 中引入的,它允许更便捷地根据特定的条件删除元素,而不必手动编写循环。
filter
:一个函数式接口 Predicate
,用于定义删除元素的条件。该谓词接受一个参数,该参数表示集合中的元素,返回一个布尔值来指示是否应删除该元素。removeIf
方法返回一个布尔值,表示是否在执行过程中修改了集合。如果有一个或多个元素被删除,它将返回 true
,否则返回 false
。removeIf
方法会遍历集合中的每个元素,并应用指定的谓词(Predicate
)来检查每个元素。对于谓词返回 true
的元素,将从集合中删除。这个方法会修改调用它的 ArrayList。removeIf
方法的示例,假设我们有一个 ArrayList 存储整数,并且要删除所有偶数元素:ArrayList<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6));
boolean result = numbers.removeIf(n -> n % 2 == 0);
System.out.println("是否有元素被删除: " + result);
System.out.println("更新后的 ArrayList: " + numbers);
// 输出
是否有元素被删除: true
更新后的 ArrayList: [1, 3, 5]
在这个示例中,removeIf
方法使用 lambda 表达式作为谓词,检查每个元素是否为偶数(n % 2 == 0
)。符合条件的元素被删除,方法返回 true
,并且 ArrayList 更新为 [1, 3, 5]
。
使用 removeIf
方法可以大大简化从 ArrayList 中删除满足特定条件的元素的操作,使代码更加简洁和可读。
E get(int index)
返回此列表中指定位置的元素。
System.out.println(list1.get(0));// a
E set(int index, E element)
用指定的元素替换此列表中指定位置的元素,并返回老值。
System.out.println(list1.set(0, "g"));// a
System.out.println(list1.get(0));// g
object[] toArray()
返回一个包含此列表中所有元素的对象数组。
<T> T[]
toArray(T[] a)
方法返回一个数组,该数组包含了 ArrayList 中的元素。这个数组的类型是由传入的目标数组类型决定的。
toArray
方法将 ArrayList 中的元素复制到目标数组中,并返回该数组。如果传入的目标数组足够大以容纳所有元素,那么元素将存储在目标数组中。如果目标数组过小,将会创建一个新的数组,并将元素复制到新数组中。如果目标数组大于 ArrayList 的大小,多余的数组元素将被设置为 null
。如果目标数组足够大,但是 ArrayList 包含的元素数量小于数组的大小,数组的部分元素将保持不变。
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
// Integer[] arr = new Integer[list.size()];
// list.toArray(arr);
// 5 6 行可以简写为
Integer[] arr = list.toArray(new Integer[list.size()]);
System.out.println(arr.getClass().getSimpleName());// Integer[]
for (Integer i : arr) System.out.println(i);// 1 2 3
trimToSize()
trimToSize()
是 Java ArrayList 类的一个方法,用于优化 ArrayList 的存储空间。当 ArrayList 的实际元素数量远小于其容量时,trimToSize()
方法可以减小 ArrayList 的内部数组的大小,以节省内存。这个方法在某些情况下可以用来提高性能和节省资源。
调用 ArrayList 公共方法 add(E e)
modCount
是集合的一个字段,它记录了对集合的结构性修改的次数。每当集合发生添加、删除或其他结构性修改时,modCount
值都会增加。modCount
主要用于迭代器(如 Iterator
、ListIterator
)来检测在迭代期间是否对集合进行了结构性修改。当迭代器初始化时,它会记录当前的 modCount
值,然后在每次迭代操作(如 next()
或 hasNext()
)之前检查 modCount
是否与初始值相同。如果它们不同,迭代器会抛出 ConcurrentModificationException
异常,以指示在迭代期间发生了结构性修改。(与扩容无关不做详细解释)
在增加修改次数后调用了私有的add方法
参数解释:
elementData
数组来存储元素s :集合大小(实际元素数量)
e : 我们添加的数据
如果当前集合大小和elementData
容量相等时需要调用grow()
对集合进行扩容
grow()
方法:
grow(int minCapacity)
方法的一个包装方法,通常在需要添加新元素时调用。grow(size + 1)
来确定新的容量,其中 size
表示当前 ArrayList 中的元素数量。size + 1
传递给 grow(int minCapacity)
表示需要添加一个元素,以此大小计算新容量。grow(int minCapacity)
方法:
minCapacity
参数表示所需的最小容量,通常是当前元素数量与要添加的元素数量之和。它用来确定新数组的大小。oldCapacity
。elementData
数组是否为空或是否等于 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
,DEFAULTCAPACITY_EMPTY_ELEMENTDATA
是一个常量,表示一个空 ArrayList 的默认空数组。DEFAULTCAPACITY_EMPTY_ELEMENTDATA
,它计算一个新的容量 newCapacity
,以确保能够容纳足够的元素。newLength
方法通常用于计算新的容量,它考虑了最小增长(minCapacity - oldCapacity
)和首选增长(oldCapacity >> 1
)。Arrays.copyOf
方法创建一个新的数组,将旧数组中的元素复制到新数组中,并返回新数组。这里可以看到 如果创建ArrayList时没有指定大小,在第一次add的时候会初始化elementData
的容量为DEFAULT_CAPACITY也就是10
新容量的计算函数newLength(int oldLength, int minGrowth, int prefGrowth)
oldCapacity
:表示当前 ArrayList 内部数组的容量,也就是当前数组可以容纳的元素数量。minCapacity - oldCapacity
:表示需要增加的最小容量,即要添加的元素数量与当前容量之间的差值。这是确保新容量足够大以容纳新元素的最小需求。oldCapacity >> 1
:表示当前容量的一半,这是一种常见的扩容策略,以确保新容量足够大,同时避免过度分配内存。将当前容量除以 2 可以使新容量大致是当前容量的 1.5 倍。prefLength
计算:首先,方法计算 prefLength
,这是 oldLength
加上 minGrowth
和 prefGrowth
中的最大值。这个值表示所需容量的一种估计,可能会超出所需的容量。prefLength
大于 0 且小于或等于 SOFT_MAX_ARRAY_LENGTH
,则返回 prefLength
。这是为了确保新容量在合理的范围内,同时防止溢出。prefLength
超出合理范围,将调用 hugeLength
方法来确定新容量。这个部分的代码通常是在冷路径(不常执行的代码路径)中的,因为大多数情况下不会触发这个分支。这个方法的目的是计算新容量,以便在需要扩展 ArrayList 内部数组时分配足够的空间来容纳更多元素。它尝试根据 minGrowth
和 prefGrowth
来估算新容量,同时确保不会出现溢出情况。如果估算的容量在合理范围内,就返回这个容量值,否则将调用 hugeLength
方法来决定新容量。
请注意,SOFT_MAX_ARRAY_LENGTH
是一个常数,表示 ArrayList 内部数组的最大允许容量,大小为 Integer.MAX_VALUE - 8
可以看出一般情况下ArrayList的扩容因子是1.5,特殊情况是(1 + minGrowth/oldLength)
ps: 演示代码的JDK版本是17,JDK8写法不一样但原理差不多。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。