Java List的基本概念与创建
在Java中,List是一种重要的集合接口,它继承自Collection接口,代表一个有序、可重复的元素序列,List的主要特点包括允许元素重复、支持按索引访问元素,以及提供动态扩容的能力,Java中常用的List实现类有ArrayList、LinkedList和Vector,它们各有特点,适用于不同的场景。

要使用List,首先需要创建其实例对象,最常见的方式是通过ArrayList或LinkedList进行初始化。
List<String> list = new ArrayList<>(); // 基于动态数组实现 List<Integer> linkedList = new LinkedList<>(); // 基于链表实现
在Java 7及以上版本,可以使用钻石运算符<>简化代码,避免重复指定泛型类型,Vector是一个线程安全的List实现类,但在现代开发中较少使用,因为更高效的并发工具(如CopyOnWriteArrayList)已经出现。
List元素的添加与遍历
List提供了多种添加元素的方法,其中最常用的是add(E e),该方法将元素追加到列表末尾。
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Orange");
如果需要在指定位置插入元素,可以使用add(int index, E e)方法:
fruits.add(1, "Mango"); // 在索引1的位置插入"Mango"
addAll(Collection<? extends E> c)方法可以将另一个集合中的所有元素添加到当前List中。
遍历List是日常开发中的高频操作,常见的遍历方式有以下几种:
- for循环遍历:通过索引访问元素,适用于需要修改元素的场景。
for (int i = 0; i < fruits.size(); i++) { System.out.println(fruits.get(i)); } - 增强for循环(for-each):简洁直观,适用于只读遍历。
for (String fruit : fruits) { System.out.println(fruit); } - Iterator遍历:支持在遍历过程中安全删除元素,避免并发修改异常。
Iterator<String> iterator = fruits.iterator(); while (iterator.hasNext()) { String fruit = iterator.next(); if ("Banana".equals(fruit)) { iterator.remove(); // 安全删除当前元素 } }
List元素的查询与修改
List允许通过索引快速访问和修改元素。get(int index)方法用于获取指定索引位置的元素,而set(int index, E e)方法用于替换该位置的元素。

String firstFruit = fruits.get(0); // 获取第一个元素,结果为"Apple" fruits.set(0, "Pear"); // 将第一个元素替换为"Pear"
需要注意的是,List的索引从0开始,如果传入的索引超出范围(如负数或大于等于size()),会抛出IndexOutOfBoundsException异常。
如果需要判断List中是否包含某个元素,可以使用contains(Object o)方法,它返回一个布尔值。
boolean hasApple = fruits.contains("Apple"); // 返回true或false
indexOf(Object o)和lastIndexOf(Object o)方法分别返回元素首次和最后一次出现的索引位置,如果元素不存在则返回-1。
List元素的删除与批量操作
List提供了多种删除元素的方法,remove(Object o)用于删除第一个匹配的元素,而remove(int index)用于删除指定索引位置的元素。
fruits.remove("Orange"); // 删除"Orange"
fruits.remove(0); // 删除索引0处的元素
批量操作方面,removeAll(Collection<?> c)方法可以删除所有在指定集合中存在的元素,retainAll(Collection<?> c)则保留两个集合的交集元素。
List<String> toRemove = Arrays.asList("Pear", "Mango");
fruits.removeAll(toRemove); // 从fruits中移除"Pear"和"Mango"
clear()方法用于清空整个List,使其不包含任何元素。
List的常用工具方法
Java提供了java.util.Collections工具类,包含了许多操作List的静态方法。

sort(List<T> list):对List进行自然排序(元素需实现Comparable接口)。List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5); Collections.sort(numbers); // 排序后为[1, 1, 3, 4, 5]
reverse(List<?> list):反转List中元素的顺序。shuffle(List<?> list):随机打乱List元素的顺序。binarySearch(List<? extends Comparable<? super T>> list, T key):二分查找,要求List已排序。
对于不可变List的创建,Java 9及以上版本提供了List.of()方法,它返回一个不可变List,任何修改操作都会抛出UnsupportedOperationException。
List<String> immutableList = List.of("A", "B", "C");
ArrayList与LinkedList的选择
在实际开发中,ArrayList和LinkedList是最常用的List实现类,它们的性能差异主要体现在操作效率上:
- ArrayList:基于动态数组实现,随机访问(
get和set)的时间复杂度为O(1),但插入和删除元素时(尤其是中间位置)需要移动元素,时间复杂度为O(n),适用于频繁查询、少量修改的场景。 - LinkedList:基于双向链表实现,插入和删除元素的时间复杂度为O(1)(已知节点位置),但随机访问需要遍历链表,时间复杂度为O(n),适用于频繁插入、删除、少量查询的场景。
在需要频繁在列表头部插入元素时,LinkedList的性能明显优于ArrayList:
List<Integer> arrayList = new ArrayList<>();
List<Integer> linkedList = new LinkedList<>();
// 在头部插入10000次
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
arrayList.add(0, i); // 每次插入需要移动所有元素
}
long end = System.currentTimeMillis();
System.out.println("ArrayList耗时: " + (end - start) + "ms");
start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
linkedList.add(0, i); // 直接修改链表指针,无需移动元素
}
end = System.currentTimeMillis();
System.out.println("LinkedList耗时: " + (end - start) + "ms");
List的线程安全问题
在多线程环境中,如果多个线程同时修改一个List实例,可能会导致数据不一致或并发修改异常(ConcurrentModificationException),Java提供了多种线程安全的List实现:
- Vector:通过
synchronized方法保证线程安全,但性能较低,已不推荐使用。 - **Collections.synchronizedList(List
list)`:将普通List包装成线程安全的List,但需要在外部加锁才能保证复合操作的原子性。 - **CopyOnWriteArrayList`:写入时复制,适用于读多写少的场景,每次修改都会创建一个新数组,保证线程安全的同时,读操作无需加锁。
使用CopyOnWriteArrayList:
List<String> threadSafeList = new CopyOnWriteArrayList<>();
threadSafeList.add("Thread1");
threadSafeList.add("Thread2");
Java List作为集合框架的核心接口,提供了丰富的操作方法,适用于需要有序存储和重复元素的场景,通过合理选择ArrayList、LinkedList等实现类,并结合遍历、查询、修改、删除等操作,可以高效地处理各种数据需求,在实际开发中,还需根据场景考虑性能优化和线程安全问题,以确保代码的健壮性和可维护性。


















