前言:
Collection集合,List集合
文章目录
- 一、Collection 集合
- 1.1 集合和数组的区别
- 1.2 集合框架
- 1.3 Collection 集合常用方法
- 1.4 Collction 集合的遍历
- 二、List 集合
- 2.1 List 概述
- 2.2 List集合的五种遍历方式
- 2.3 List集合的实现类
一、Collection 集合
1.1 集合和数组的区别
- 大小
- 数组:大小是固定的。在创建数组时,需要指定数组的大小,一旦创建,数组的大小就不能改变。
- 集合:大小是可变的。集合类(如 ArrayList、HashSet 等)可以根据需要动态地增加或减少元素。
- 类型
- 数组:可以存储基本数据类型(如 int、char)和对象类型。
- 集合:只能存储对象类型,不能直接存储基本数据类型。不过,可以使用基本数据类型的包装类(如 Integer、Character)。
- 存储结构
- 数组:连续的内存空间,元素可以通过索引直接访问,访问速度快。
- 集合:底层实现可能是链表、哈希表、红黑树等,具体取决于集合的实现类。
- 功能
- 数组:没有预定义的方法来操作数组元素,只能通过基本的循环和手动实现操作(如添加、删除、查找等)。
- 集合:提供了丰富的预定义方法来操作集合元素,如添加(add)、删除(remove)、查找(contains)、迭代(iterator)等。
1.2 集合框架
Collection 接口: 所有集合框架中的接口都继承自这个接口。它有以下几个子接口:
- List: 有序集合,允许重复元素。
- Set: 不允许重复元素。
- Queue: 先进先出(FIFO)的集合。
Map 接口: 一种键值对映射的集合,不属于 Collection 接口的子接口。
1.3 Collection 集合常用方法
Collection
接口中定义的这些方法是抽象方法,具体的实现由实现了 Collection
接口的具体类来完成。
方法名 | 说明 |
---|---|
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定的元素 |
boolean removeIf(Predicate<? super E> filter) | 根据条件进行移除 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否存在指定的元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中元素的个数 |
1.4 Collction 集合的遍历
-
使用增强型 for 循环
增强型
for
循环可以很方便地遍历集合,它适用于所有实现了Iterable
接口的集合类,包括Collection
接口的所有实现类。import java.util.ArrayList; import java.util.Collection; public class CollectionTraversalExample { public static void main(String[] args) { Collection<String> collection = new ArrayList<>(); collection.add("Apple"); collection.add("Banana"); collection.add("Orange"); // 使用增强型 for 循环遍历集合 for (String fruit : collection) { System.out.println(fruit); } } }
-
使用迭代器(Iterator)
迭代器是遍历集合的一种标准方式,它允许按顺序访问集合中的每个元素,并且可以在遍历过程中进行元素的增删操作。
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class CollectionTraversalExample { public static void main(String[] args) { Collection<String> collection = new ArrayList<>(); collection.add("Apple"); collection.add("Banana"); collection.add("Orange"); // 调用集合的 iterator() 方法来获取该集合的迭代器。迭代器是一个对象,它提供了顺序访问集合元素的方法,并且允许在遍历过程中进行安全的元素删除操作。 Iterator<String> iterator = collection.iterator(); // 使用 hasNext() 方法判断当前位置是否有元素可以被取出 while (iterator.hasNext()) { //next()获取当前位置的元素,将迭代器对象移向下一个索引位置 String fruit = iterator.next(); System.out.println(fruit); } } }
-
forEach 方法,传入 lambda 表达式
import java.util.ArrayList; import java.util.Collection; public class CollectionTraversalExample { public static void main(String[] args) { Collection<String> collection = new ArrayList<>(); collection.add("Apple"); collection.add("Banana"); collection.add("Orange"); // 或者使用 forEach 方法,传入 lambda 表达式,fruit -> System.out.println(fruit) 是匿名内部类对象 collection.forEach(fruit -> System.out.println(fruit)); } }
在 forEach 方法中,我们传入一个 Lambda 表达式 fruit -> System.out.println(fruit)。这个 Lambda 表达式定义了一个行为,即对每个元素执行 System.out.println(fruit) 操作。
注意事项
- 并发修改异常:在使用迭代器遍历集合时,如果在遍历过程中修改了集合的结构(如添加、删除元素),会抛出
ConcurrentModificationException
异常。这种情况下,可以使用迭代器的remove()
方法来安全地删除元素。
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
if (fruit.equals("Banana")) {
iterator.remove(); // 安全删除元素
}
}
二、List 集合
2.1 List 概述
List 集合的特点:
-
有序性: List 是有序集合,它维护元素的插入顺序。可以通过索引访问元素,索引从 0 开始,依次递增。
-
允许重复元素: 与 Set 不同,List 允许存储重复的元素。
List 特有方法:
方法名 | 描述 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
int indexOf(Object o) | indexOf 方法返回指定元素第一次出现在列表中的索引,如果列表不包含该元素,则返回 -1 |
int lastIndexOf(Object o) | lastIndexOf 方法返回指定元素最后一次出现在列表中的索引,如果列表不包含该元素,则返回 -1 |
boolean addAll(int index, Collection<? extends E> c) | 在指定位置 index 处将另一个集合 c 中的所有元素插入到列表中。如果 c 为空集合,此方法不会改变列表,返回 false |
void sort(Comparator<? super E> c) | 使用指定的比较器 c 对列表进行排序。如果没有提供比较器,则列表中的元素必须实现 Comparable 接口以便进行自然排序 |
2.2 List集合的五种遍历方式
- 迭代器
- 增强for
- Lambda表达式
- 普通for循环
- 列表迭代器
List
接口继承自Collection
接口,相比于Collection
,List
多出两种遍历方式:普通for循环和使用 ListIterator
。
- 使用普通的 for 循环
普通的 for 循环可以通过索引来遍历 List
集合。这种方式适用于需要获取每个元素的索引或需要条件判断的情况。
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
for (int i = 0; i < list.size(); i++) {
String element = list.get(i);
System.out.println(element);
}
- 使用 ListIterator
ListIterator
是 Iterator
的子接口,它扩展了迭代器的功能,支持双向遍历、修改元素和获取索引等操作。适用于需要在遍历过程中修改元素或者双向遍历的场景。
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
String element = listIterator.next();
System.out.println(element);
}
使用 ListIterator 进行操作
-
正向遍历: 使用 hasNext() 和 next() 方法遍历列表。
while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); }
-
反向遍历: 使用 hasPrevious() 和 previous() 方法反向遍历列表。
while (iterator.hasPrevious()) { String element = iterator.previous(); System.out.println(element); }
-
修改元素: 可以使用 set() 方法修改当前遍历到的元素。
// 修改第一个元素为 "Grapes" iterator.next(); // 移动到第一个元素 iterator.set("Grapes");
-
添加元素: 可以使用 add() 方法在当前位置之前添加新元素。
// 在当前位置之前添加 "Mango" iterator.add("Mango");
-
删除元素: 可以使用 remove() 方法删除当前位置的元素(需要先调用 next() 或 previous() 方法)。
// 删除当前位置的元素 iterator.next(); iterator.remove();
2.3 List集合的实现类
在 Java 中,List
是一个接口,它有多个常见的实现类,每种实现类都有其独特的特性和适用场景。以下是几种常见的 List
接口的实现类:
-
ArrayList
ArrayList
是List
接口的可变大小数组实现。- 它提供了动态增长的能力,支持快速随机访问元素。
- 插入和删除元素可能比较慢,因为需要调整内部数组的大小。
- 适用于需要快速访问元素而对插入和删除操作性能要求不那么苛刻的场景。
List<String> arrayList = new ArrayList<>();
ArrayList 的扩容机制如下:
-
初始容量:
创建ArrayList
对象的时候,他在底层先创建了一个长度为0的数组。只有当第一个元素被添加时,ArrayList
才会分配默认的初始容量,这个默认初始容量通常是 10。 -
添加元素时的自动扩容:
每次向 ArrayList 添加元素时,它会检查当前元素数量是否已经达到容量上限。如果当前元素数量等于或超过当前容量(即size() >= capacity
),就会触发扩容操作。 -
扩容机制:
- 机制一: 扩容操作会创建一个新的数组,通常新容量为原来的 1.5 倍(有时候是倍增,具体取决于 JVM 的实现)。例如,如果当前容量为 10,则扩容后的容量可能为 15。
- 机制二: 如果一次性添加多个数据,新添加的数据加上原来的数据还是超过了1.5倍的容量,那么新创建数组的长度以实际为准。例如,原有的容量为10,并且已满,现在我们要再添加10个数据,即使根据机制一还是不够,那么新数组的容量就变为20。
- 然后,将原来数组中的所有元素复制到新的数组中。
- 最后,原来的数组会被丢弃(即成为垃圾对象等待垃圾回收)。
-
LinkedList
LinkedList
是List
接口的双向链表实现。- 它提供了快速的插入和删除操作,但访问速度相对较慢(需要从头或尾部遍历链表)。
- 支持队列和双端队列操作,如
offerFirst()
,offerLast()
,pollFirst()
,pollLast()
等。 - 适用于需要频繁进行插入和删除操作,而对随机访问元素的要求不高的场景。
List<String> linkedList = new LinkedList<>();
-
Vector
Vector
是 Java 集合框架中较早的实现类,现在较少使用。- 与
ArrayList
类似,它也是一个动态增长的数组实现。 - 它是线程安全的,所有方法都使用
synchronized
进行了同步。 - 适用于需要线程安全且不需要高性能的场景。
List<String> vector = new Vector<>();
如果你喜欢这篇文章,点赞👍+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。