杰瑞科技汇

java arraylist 长度

  • 大小:指的是 ArrayList 当前实际存储了多少个元素,这是我们通常所说的“长度”。
  • 容量:指的是 ArrayList 底层数组能够容纳多少个元素,而无需重新分配内存。

获取 ArrayList 的大小(实际长度)

这是最常见的需求,即想知道 ArrayList 中有多少个元素。ArrayList 类提供了一个 size() 方法来获取这个值。

java arraylist 长度-图1
(图片来源网络,侵删)

size() 方法

  • 作用:返回列表中的元素数量。
  • 返回值:一个 int 类型,表示当前列表的大小。
  • 重要:这个值不等于 ArrayList 的容量。

示例代码:

import java.util.ArrayList;
public class ArrayListSizeExample {
    public static void main(String[] args) {
        // 创建一个初始容量为 10 的 ArrayList
        ArrayList<String> fruits = new ArrayList<>(10);
        System.out.println("初始时,ArrayList 的大小: " + fruits.size()); // 输出 0
        // 添加元素
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        System.out.println("添加 3 个元素后,ArrayList 的大小: " + fruits.size()); // 输出 3
        // 清空 ArrayList
        fruits.clear();
        System.out.println("清空后,ArrayList 的大小: " + fruits.size()); // 输出 0
    }
}

输出:

初始时,ArrayList 的大小: 0
添加 3 个元素后,ArrayList 的大小: 3
清空后,ArrayList 的大小: 0

ArrayList 的容量

ArrayList 的内部是基于一个数组实现的,当你创建 ArrayList 时,它会创建一个初始的内部数组,当这个数组被填满后,如果再添加元素,ArrayList 会自动创建一个更大的新数组,并将旧数组中的元素复制过去,这个自动扩容的过程是性能开销较大的操作。

java arraylist 长度-图2
(图片来源网络,侵删)

如何查看和设置容量?

a. 初始容量

在创建 ArrayList 时,可以指定一个初始容量。

构造方法 ArrayList(int initialCapacity)

  • 作用:创建一个具有指定初始容量的空列表。
  • 优点:如果你大致知道要存储多少元素,指定一个合适的初始容量可以避免在添加元素过程中频繁地进行扩容操作,从而提高性能。

示例代码:

java arraylist 长度-图3
(图片来源网络,侵删)
// 创建一个初始容量为 5 的 ArrayList
ArrayList<Integer> numbers = new ArrayList<>(5);
System.out.println("初始容量: " + numbers.size()); // size() 返回的是大小,不是容量
// 注意:没有直接获取容量的 public 方法,但可以通过反射等方式获取,通常不推荐。

b. 自动扩容

当你向 ArrayList 中添加元素,并且当前大小等于容量时,ArrayList 就会进行扩容。

  • 默认扩容机制:新的容量会是旧容量的 5 倍
  • 扩容过程
    1. 创建一个更大的新数组(容量为 oldCapacity * 1.5)。
    2. 将旧数组中的所有元素复制到新数组中。
    3. 将新数组赋值给 ArrayList 的内部引用,旧数组被垃圾回收。

示例代码:

import java.util.ArrayList;
public class ArrayListCapacityExample {
    public static void main(String[] args) {
        // 创建一个初始容量为 3 的 ArrayList
        ArrayList<String> list = new ArrayList<>(3);
        System.out.println("初始大小: " + list.size()); // 0
        // 注意:没有直接获取容量的标准方法,我们通过反射来观察(仅用于演示)
        try {
            java.lang.reflect.Field field = ArrayList.class.getDeclaredField("elementData");
            field.setAccessible(true);
            Object[] elementData = (Object[]) field.get(list);
            System.out.println("初始容量: " + elementData.length); // 3
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 添加元素,触发扩容
        list.add("A");
        list.add("B");
        list.add("C"); // size=3, capacity=3,数组已满
        System.out.println("添加 3 个元素后,大小: " + list.size()); // 3
        list.add("D"); // 添加第 4 个元素,将触发扩容
        System.out.println("添加第 4 个元素后,大小: " + list.size()); // 4
        // 再次通过反射查看容量
        try {
            java.lang.reflect.Field field = ArrayList.class.getDeclaredField("elementData");
            field.setAccessible(true);
            Object[] elementData = (Object[]) field.get(list);
            System.out.println("扩容后的容量: " + elementData.length); // 4.5 -> 4 (JVM会取整) 或者 6 (取决于JVM实现,但通常是1.5倍)
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出(可能因JVM版本不同而略有差异):

初始大小: 0
初始容量: 3
添加 3 个元素后,大小: 3
添加第 4 个元素后,大小: 4
扩容后的容量: 6  // 3 * 1.5 = 4.5,向上取整为5,但JVM内部实现通常是取整为最近的2的幂次方或直接使用1.5倍并取整,这里是6

c. 手动调整容量

ArrayList 提供了一个 trimToSize() 方法,可以用来手动调整容量。

trimToSize() 方法

  • 作用:将 ArrayList 的容量调整为当前列表的大小。
  • 使用场景:当你已经完成了所有元素的添加,并且确定不会再添加新元素时,可以调用此方法来释放多余的内存,减少内存占用。

示例代码:

import java.util.ArrayList;
public class ArrayListTrimToSizeExample {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(10); // 初始容量为 10
        list.add("One");
        list.add("Two");
        System.out.println("当前大小: " + list.size()); // 2
        // 假设我们通过反射看到容量是 10
        list.trimToSize(); // 将容量修剪为当前大小
        System.out.println("修剪后的大小: " + list.size()); // 大小不变,仍然是 2
        // 通过反射可以看到,现在容量也变成了 2
        System.out.println("修剪后的容量 (通过反射观察): " + getCapacity(list)); // 2
    }
    // 辅助方法,用于获取 ArrayList 的容量(仅用于演示)
    public static int getCapacity(ArrayList<?> list) {
        try {
            java.lang.reflect.Field field = ArrayList.class.getDeclaredField("elementData");
            field.setAccessible(true);
            Object[] elementData = (Object[]) field.get(list);
            return elementData.length;
        } catch (Exception e) {
            return -1; // 发生错误
        }
    }
}

总结与最佳实践

概念 获取/设置方法 描述
大小 list.size() 这是你通常想要的“长度”,表示当前存储的元素数量。
容量 new ArrayList<>(initialCapacity)
list.trimToSize()
内部数组的长度,影响扩容性能。

最佳实践:

  1. 明确需求:当你问“长度”时,请确定你指的是 size() 还是 capacity,99% 的情况下,你需要的是 size()
  2. 预估容量:如果你预先知道 ArrayList 大概要存放多少元素,在创建时使用 new ArrayList<>(estimatedSize) 可以显著提高性能,因为它避免了在添加过程中的多次扩容。
  3. 适时修剪ArrayList 在填充了少量元素后需要被长期保存,并且不会再增长,调用 trimToSize() 是一个很好的内存优化习惯。
  4. 不要使用 list.toArray().length:虽然 toArray() 返回的数组长度等于 list.size(),但创建一个新数组是有性能开销的,直接使用 list.size() 是最直接、最高效的方式。
分享:
扫描分享到社交APP
上一篇
下一篇