Java ArrayList 类

2024-04-25 16:38:27 浏览数 (1)

hi,今天我们来聊聊Java中的ArrayList~

ArrayList基础

ArrayList简介

ArrayList 是Java集合框架中的一个类,位于 java.util 包下。它实现了 List 接口以及其所有可选的接口,如 Serializable(可序列化)和 Cloneable(可克隆)。ArrayList 是一个动态数组,可以存储任意数量的非原始类型对象。

创建ArrayList实例

创建 ArrayList 实例非常简单,可以通过默认构造方法或带有初始容量的构造方法来实现。

默认构造方法

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();

指定初始容量的构造方法

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>(10); // 初始容量为10
ArrayList的属性和初始容量

ArrayList 的初始容量是指在添加元素时不需要进行扩容操作的最小容量。如果初始容量设置得过高,而实际存储的元素较少,这将浪费内存;如果设置得过低,那么随着元素的增加,ArrayList 将不得不进行多次扩容操作,这将降低性能。

案例源码说明

创建并初始化ArrayList

代码语言:javascript复制
// 创建一个空的ArrayList,用于存储String类型的对象
ArrayList<String> fruits = new ArrayList<>();

// 向ArrayList中添加元素
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Cherry");

// 打印ArrayList中的元素
System.out.println(fruits);

使用指定初始容量的构造方法

代码语言:javascript复制
// 创建一个初始容量为5的ArrayList
ArrayList<Integer> numbers = new ArrayList<>(5);

// 向ArrayList中添加元素
numbers.add(1);
numbers.add(2);
numbers.add(3);

// 打印ArrayList的初始容量
System.out.println("Initial Capacity: "   numbers.capacity());

ArrayList的扩容机制 ArrayList 的容量自动增长,但是当添加的元素超过当前容量时,会创建一个更大的数组来存储所有元素,并把旧的元素复制到新数组中。

代码语言:javascript复制
// 创建一个初始容量为2的ArrayList
ArrayList<String> smallList = new ArrayList<>(2);

// 连续添加超过初始容量的元素,触发扩容
smallList.add("One");
smallList.add("Two");
smallList.add("Three");

// 打印当前容量
System.out.println("Current Capacity: "   smallList.capacity());

ArrayList操作

元素添加

ArrayList 提供了多种添加元素的方法,包括在末尾添加单个元素或整个集合,以及在指定位置插入一个或多个元素。

add(E e)

在列表末尾添加一个元素。

示例:

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
// 添加单个元素到列表末尾
list.add("Element 1");
list.add("Element 2");
System.out.println(list); // 输出: [Element 1, Element 2]
add(int index, E element)

在指定位置插入一个元素。

示例:

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
list.add("First");
list.add("Third");
// 在索引 1 的位置插入 "Second"
list.add(1, "Second");
System.out.println(list); // 输出: [First, Second, Third]
元素访问

通过索引访问列表中的元素。

get(int index)

返回指定位置的元素。

示例:

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
// 获取索引1的元素
String fruit = list.get(1);
System.out.println(fruit); // 输出: Banana
元素删除

ArrayList 提供了几种删除元素的方法。

remove(int index)

删除指定位置的元素,并返回被删除的元素。

示例:

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
// 删除索引1的元素
String removed = list.remove(1);
System.out.println(removed); // 输出: Banana
System.out.println(list); // 输出: [Apple, Cherry]
remove(Object o)

删除列表中第一次出现的指定元素。

示例:

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
// 删除指定的对象
boolean isRemoved = list.remove("Banana");
System.out.println(isRemoved); // 输出: true
System.out.println(list); // 输出: [Apple]
元素搜索

ArrayList 提供了搜索元素的方法。

contains(Object o)

检查列表是否包含指定的元素。

示例:

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
// 检查列表是否包含 "Cherry"
boolean contains = list.contains("Cherry");
System.out.println(contains); // 输出: false
indexOf(Object o)

返回指定元素在列表中第一次出现的索引。

示例:

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
// 获取 "Banana" 在列表中的索引
int index = list.indexOf("Banana");
System.out.println(index); // 输出: 1
案例源码说明

以下是 ArrayList 操作的完整示例,包括添加、访问、删除和搜索元素:

代码语言:javascript复制
public class ArrayListExample {
    public static void main(String[] args) {
        // 创建一个ArrayList
        ArrayList<String> fruits = new ArrayList<>();

        // 使用add方法添加元素到ArrayList
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add(0, "Apricot"); // 在索引0的位置插入

        // 使用get方法访问特定位置的元素
        String fruit = fruits.get(1);
        System.out.println("Fruit at index 1: "   fruit);

        // 使用remove方法删除特定位置的元素
        String removedFruit = fruits.remove(2);
        System.out.println("Removed fruit: "   removedFruit);

        // 使用contains方法检查元素是否存在
        boolean hasCherry = fruits.contains("Cherry");
        System.out.println("Contains Cherry: "   hasCherry);

        // 使用indexOf方法获取元素的索引
        int indexOfBanana = fruits.indexOf("Banana");
        System.out.println("Index of Banana: "   indexOfBanana);

        // 打印ArrayList的当前状态
        System.out.println("Current fruits list: "   fruits);
    }
}

ArrayList高级特性

列表迭代

ArrayList 支持两种主要的迭代方式:使用传统的 for 循环和使用 Iterator

使用for-each循环
代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C  ");

// 使用for-each循环迭代ArrayList
for (String language : list) {
    System.out.println(language);
}
使用迭代器
代码语言:javascript复制
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C  ");

// 使用迭代器迭代ArrayList
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String language = iterator.next();
    System.out.println(language);
}
列表排序

ArrayList 可以通过 Collections 类或自定义的 Comparator 进行排序。

Collections.sort()
代码语言:javascript复制
List<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("C  ");

// 使用Collections.sort()方法对ArrayList进行自然排序
Collections.sort(languages);
System.out.println(languages);
自定义排序
代码语言:javascript复制
List<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("C  ");

// 使用自定义Comparator进行排序
Collections.sort(languages, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s2.compareTo(s1); // 倒序排序
    }
});
System.out.println(languages);
列表容量管理

ArrayList 允许开发者手动管理其容量。

ensureCapacity()
代码语言:javascript复制
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);

// 确保ArrayList至少能容纳n个元素
numbers.ensureCapacity(10);

System.out.println("Current Capacity: "   numbers.capacity());
trimToSize()
代码语言:javascript复制
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);

// 调整ArrayList的容量以匹配其大小
numbers.trimToSize();

System.out.println("Trimmed Capacity: "   numbers.capacity

());
案例源码说明

以下是 ArrayList 高级特性的完整示例,包括迭代、排序和容量管理:

代码语言:javascript复制
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

public class ArrayListAdvanced {
    public static void main(String[] args) {
        // 初始化ArrayList
        ArrayList<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("C  ");

        // 迭代ArrayList
        System.out.println("Iterating ArrayList:");
        for (String language : list) {
            System.out.println(language);
        }

        // 使用迭代器迭代ArrayList
        System.out.println("Iterating with Iterator:");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String language = iterator.next();
            System.out.println(language);
        }

        // 排序ArrayList
        System.out.println("Sorted ArrayList (natural order):");
        Collections.sort(list);
        System.out.println(list);

        // 使用自定义Comparator排序ArrayList
        System.out.println("Sorted ArrayList (custom order):");
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                return s2.compareTo(s1);
            }
        });
        System.out.println(list);

        // 容量管理
        ArrayList<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);

        System.out.println("Before ensureCapacity: "   numbers.capacity());
        numbers.ensureCapacity(5);
        System.out.println("After ensureCapacity: "   numbers.capacity());

        numbers.trimToSize();
        System.out.println("After trimToSize: "   numbers.capacity());
    }
}

ArrayList与性能

时间复杂度分析

ArrayList 的性能通常取决于操作的类型。以下是一些常见操作的时间复杂度:

  • 添加元素 (add(E e), add(int index, E element)): 平均时间复杂度为 O(1),但如果需要扩容,则为 O(n)。
  • 获取元素 (get(int index)): 时间复杂度为 O(1)。
  • 删除元素 (remove(int index), remove(Object o)): 时间复杂度为 O(n),因为可能需要移动元素。
  • 搜索元素 (contains(Object o), indexOf(Object o)): 时间复杂度为 O(n)。
性能考量与优化建议

由于 ArrayList 是一个动态数组,它的性能特点需要根据使用场景来考虑:

  • 频繁的插入和删除:如果对列表的中间位置进行频繁的插入和删除操作,性能会受到影响,因为 ArrayList 需要移动元素来维护数组的连续性。在这种情况下,考虑使用 LinkedList
  • 随机访问:如果需要频繁地进行随机访问,ArrayList 是一个好的选择,因为它提供了 O(1) 的时间复杂度。
  • 初始化容量:尽量预估列表的大小并设置合适的初始容量,以避免频繁的数组扩容操作。
案例源码说明

以下是 ArrayList 性能考量的示例:

频繁插入与删除的示例

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
// 模拟频繁的添加和删除操作
for (int i = 0; i < 10000; i  ) {
    list.add("Element "   i);
    if (i % 1000 == 0) {
        list.remove(i - 1);
    }
}

在这个示例中,我们模拟了一个包含频繁插入和删除的场景。如果列表很大,这会触发多次数组复制,导致性能下降。

随机访问的示例

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>();
// 填充ArrayList
for (int i = 0; i < 1000; i  ) {
    list.add("Element "   i);
}

// 随机访问特定位置的元素
long startTime = System.nanoTime();
String element = list.get(999); // 假设我们要访问接近末尾的元素
long endTime = System.nanoTime();
System.out.println("Random access time: "   (endTime - startTime)   " ns");

在这个示例中,我们展示了 ArrayList 随机访问的性能。由于是直接通过索引访问,所以操作非常快速。

初始化容量的示例

代码语言:javascript复制
ArrayList<String> list = new ArrayList<>(1000); // 设置初始容量为1000
// 填充ArrayList
for (int i = 0; i < 1000; i  ) {
    list.add("Element "   i);
    // 由于初始容量已足够,这里不会触发扩容操作
}

0 人点赞