整体介绍
Java集合框架(Java Collection Framework, JCF)是Java编程语言中用于存储、组织和操作数据的一个重要部分,它提供了一组接口、抽象类以及实现这些接口的具体类,用来管理对象集合。Java集合框架主要包括以下核心组成部分:
-
顶层接口
java.util.Collection
:所有单列集合(如列表、集合、队列等)的根接口,定义了基本的集合操作方法,如添加、删除、检查元素是否存在等。java.util.Map
:双列集合的根接口,表示键值对映射关系,提供了根据键查找值、插入、删除键值对等功能。
-
子接口
java.util.List
:有序且允许重复元素的集合,例如ArrayList
、LinkedList
、Vector
等。java.util.Set
:无序且不允许重复元素的集合,例如HashSet
、TreeSet
等。java.util.Queue
和java.util.Deque
:分别代表先进先出(FIFO)和双端队列(可以从两端添加或移除元素)的集合接口。
-
迭代器接口
java.util.Iterator
:所有集合类都通过此接口提供遍历其元素的能力。java.utilSpliterator
:为并行处理提供更高级别的迭代能力。
-
其他辅助接口
java.util.Comparator
:用于比较对象的接口,可以自定义排序规则。java.lang.Comparable
:对象如果实现了这个接口,就可以自然排序。
-
抽象类
java.util.AbstractCollection
和java.util.AbstractList
、AbstractSet
等抽象类,它们实现了 Collection 接口的部分或全部方法,并为具体集合类的实现提供了便利。
-
实现类
- 如
ArrayList
、LinkedList
、HashSet
、HashMap
等具体的集合实现类,它们实现了上述接口,提供了实际的数据存储结构。
- 如
-
工具类与算法
java.util.Collections
类提供了大量静态方法来操作集合,如排序、搜索、填充等。java.util.stream.Stream
API 提供了基于流的集合操作方式。
Java集合体系的目标是提供一致性和灵活性,使得开发者可以根据不同的需求选择最适合的数据结构进行开发,同时能够高效地执行各种集合相关的操作。
List
常用的ArryList,LinkedList
java.util.List
是 Java 集合框架中的一个重要接口,它表示一个有序的元素序列,允许重复元素。List 接口提供了丰富的操作方法,如添加、删除、查询、修改元素,以及对列表进行迭代等。
案例一:ArrayList 的使用
import java.util.ArrayList;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
// 创建 ArrayList 实例
List<String> list = new ArrayList<>();
// 添加元素到列表
list.add("Apple");
list.add("Banana");
list.add("Cherry");
// 在指定位置插入元素
list.add(1, "Orange");
// 输出所有元素
for (String fruit : list) {
System.out.println(fruit);
}
// 获取指定索引处的元素
String secondFruit = list.get(1);
System.out.println("Second fruit: " + secondFruit);
// 删除指定元素
list.remove("Banana");
// 判断列表是否包含某个元素
boolean containsCherry = list.contains("Cherry");
System.out.println("Does list contain Cherry? " + containsCherry);
// 获取列表大小(元素个数)
int size = list.size();
System.out.println("Size of the list: " + size);
}
}
运行上述代码,会输出:
Apple
Orange
Cherry
Second fruit: Orange
Does list contain Cherry? true
Size of the list: 3
案例二:LinkedList 的使用
import java.util.LinkedList;
import java.util.List;
public class LinkedListExample {
public static void main(String[] args) {
// 创建 LinkedList 实例
List<Integer> linkedList = new LinkedList<>();
// 添加元素到链表
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
// 使用 addFirst 和 addLast 方法
linkedList.addFirst(0); // 在头部添加元素
linkedList.addLast(4); // 在尾部添加元素
// 遍历链表
for (Integer number : linkedList) {
System.out.print(number + " ");
}
// 删除第一个元素
linkedList.removeFirst();
// 删除最后一个元素
linkedList.removeLast();
}
}
运行这段代码,将输出:
0 1 2 3 4
以上两个案例展示了 List 接口两种常见实现类 ArrayList 和 LinkedList 的基本用法。在实际开发中,根据应用场景选择合适的 List 实现类非常重要,例如,如果需要频繁地在列表中间插入和删除元素,LinkedList 可能更适合;而如果主要关注随机访问性能,则 ArrayList 更为高效。
数据结构不一样,特点也不一样。
巨大数据量的情况下
ArrayList查询快,增删慢
LinkedList 增删快,查询慢,要遍历 链表结构。
Set
java.util.Set
是 Java 集合框架中的一个接口,它表示一个不允许包含重复元素的集合。Set 接口继承自 Collection 接口,提供了添加、删除、判断是否包含等基本操作方法。
案例一:HashSet 的使用
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
// 创建 HashSet 实例
Set<String> set = new HashSet<>();
// 添加元素到集合
set.add("Apple");
set.add("Banana");
set.add("Cherry");
// 尝试添加重复元素(由于 Set 不允许重复,所以此操作无效)
set.add("Apple"); // 此操作不会影响集合内容
// 输出所有元素
for (String fruit : set) {
System.out.println(fruit);
}
// 判断集合是否包含某个元素
boolean containsCherry = set.contains("Cherry");
System.out.println("Does set contain Cherry? " + containsCherry);
// 删除指定元素
set.remove("Banana");
// 获取集合大小(元素个数)
int size = set.size();
System.out.println("Size of the set: " + size);
}
}
运行上述代码,会输出:
Apple
Banana
Cherry
Does set contain Cherry? true
Size of the set: 2
案例二:TreeSet 的使用(带有排序功能的 Set)
import java.util.TreeSet;
import java.util.Set;
public class TreeSetExample {
public static void main(String[] args) {
// 创建 TreeSet 实例
Set<String> treeSet = new TreeSet<>();
// 添加元素到集合,TreeSet 自动按字典序排序
treeSet.add("Apple");
treeSet.add("Banana");
treeSet.add("Cherry");
// 尝试添加重复元素(由于 Set 不允许重复,所以此操作无效)
treeSet.add("Apple");
// 输出所有元素(按顺序)
for (String fruit : treeSet) {
System.out.println(fruit);
}
// 使用 Comparator 定义自定义排序规则
Set<Integer> customSortedSet = new TreeSet<>((a, b) -> b - a);
customSortedSet.add(3);
customSortedSet.add(1);
customSortedSet.add(2);
// 输出按照降序排列的整数集合
for (Integer number : customSortedSet) {
System.out.print(number + " ");
}
}
}
运行这段代码,将输出:
Apple
Banana
Cherry
3 2 1
以上两个案例分别展示了 Set 接口两种常见实现类 HashSet 和 TreeSet 的基本用法。HashSet 提供了无序且不允许重复的存储结构,而 TreeSet 在此基础上增加了排序功能。在实际开发中,根据需求选择合适的 Set 实现类能够更好地满足业务场景的需求。
Map
java.util.Map
是 Java 集合框架中的一个重要接口,它代表了一种键值对(Key-Value Pair)的数据结构。Map 中的每个键都是唯一的,并且与一个对应的值相关联。以下通过案例来讲解 Map 接口及其实现类 HashMap 的使用:
案例一:HashMap 的使用
import java.util.HashMap;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
// 创建 HashMap 实例
Map<String, Integer> studentGrades = new HashMap<>();
// 添加键值对到 Map
studentGrades.put("Alice", 90);
studentGrades.put("Bob", 85);
studentGrades.put("Charlie", 95);
// 尝试添加重复键(由于 Map 键唯一,旧值将被新值替换)
studentGrades.put("Alice", 92); // Alice 的分数更新为 92
// 输出所有键值对
for (Map.Entry<String, Integer> entry : studentGrades.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 根据键获取值
int aliceGrade = studentGrades.get("Alice");
System.out.println("Alice's grade: " + aliceGrade);
// 判断 Map 是否包含某个键
boolean hasBob = studentGrades.containsKey("Bob");
System.out.println("Does map contain Bob? " + hasBob);
// 删除键值对
studentGrades.remove("Bob");
// 获取 Map 的大小(键值对个数)
int size = studentGrades.size();
System.out.println("Size of the map: " + size);
}
}
运行上述代码,会输出:
Alice: 92
Bob: 85
Charlie: 95
Alice's grade: 92
Does map contain Bob? true
Size of the map: 2
案例二:TreeMap 的使用(带有排序功能的 Map)
import java.util.TreeMap;
import java.util.Map;
public class TreeMapExample {
public static void main(String[] args) {
// 创建 TreeMap 实例,默认按键的自然顺序排序
Map<String, Integer> sortedGrades = new TreeMap<>();
// 添加键值对到 TreeMap
sortedGrades.put("Alice", 90);
sortedGrades.put("Bob", 85);
sortedGrades.put("Charlie", 95);
// 输出所有按照键排序的键值对
for (Map.Entry<String, Integer> entry : sortedGrades.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 使用自定义比较器实现按键的降序排序
Map<Integer, String> customSortedMap = new TreeMap<>((a, b) -> b - a);
customSortedMap.put(1, "First");
customSortedMap.put(3, "Third");
customSortedMap.put(2, "Second");
// 输出按照键降序排列的键值对
for (Map.Entry<Integer, String> entry : customSortedMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
运行这段代码,将会看到:
Alice: 90
Bob: 85
Charlie: 95
3: Third
2: Second
1: First
以上两个案例分别展示了 Map 接口两种常见实现类 HashMap 和 TreeMap 的基本用法。HashMap 提供了基于哈希表的无序、高效存取机制,而 TreeMap 在此基础上提供了自动排序的功能,可以根据键的自然顺序或自定义比较器进行排序。在实际应用中,根据需要选择合适的 Map 实现类能够更好地满足项目需求。
迭代器的使用
迭代器(Iterator)在Java集合框架中是用于遍历List、Set和Map集合元素的核心组件。以下是如何在这些集合中使用迭代器的示例:
在List中的使用
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorExample {
public static void main(String[] args) {
// 创建一个ArrayList实例
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
// 获取List的迭代器
Iterator<String> iterator = list.iterator();
// 遍历List
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println(fruit);
}
}
}
在Set中的使用
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class IteratorExample {
public static void main(String[] args) {
// 创建一个HashSet实例
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Cherry");
// 获取Set的迭代器
Iterator<String> iterator = set.iterator();
// 遍历Set
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println(fruit);
}
}
}
在Map中的使用
Map本身不能直接创建迭代器来遍历键值对,但可以通过调用keySet()
、values()
或entrySet()
方法获取相应的集合,再通过这些集合的迭代器遍历。
遍历Map的所有键值对:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class IteratorExample {
public static void main(String[] args) {
// 创建一个HashMap实例
Map<String, String> map = new HashMap<>();
map.put("1", "Apple");
map.put("2", "Banana");
map.put("3", "Cherry");
// 获取Map中所有键值对集合的迭代器
Iterator<Entry<String, String>> iterator = map.entrySet().iterator();
// 遍历Map的键值对
while (iterator.hasNext()) {
Entry<String, String> entry = iterator.next();
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
}
}
注意事项:
- 使用迭代器时,如果在遍历过程中修改了集合(比如删除当前项),需要特别小心,通常应该先调用
remove()
方法移除当前元素后再进行下一次迭代,否则可能会抛出异常。 - 对于List和Set的迭代可以直接使用增强for循环(foreach)简化代码。而对于Map,只能通过其entrySet的迭代器来进行类似简化。
Collections 的使用
java.util.Collections
是 Java 集合框架中一个非常重要的工具类,它提供了一系列静态方法来操作集合(如 List、Set 和 Map),这些方法可以对集合进行排序、搜索、填充、同步控制等。以下是一些 Collections
类的典型用法:
-
排序操作:
- 对 ArrayList 进行排序:
List<Integer> numbers = new ArrayList<>(); numbers.add(3); numbers.add(1); numbers.add(2); Collections.sort(numbers); // 自然排序
-
按照自定义规则排序:
List<String> names = new ArrayList<>(); names.add("Bob"); names.add("Alice"); names.add("Charlie"); Collections.sort(names, new Comparator<String>() { @Override public int compare(String s1, String s2) { return s1.compareTo(s2); // 升序排列 // 或者自定义比较逻辑,例如按字符串长度降序排列: // return Integer.compare(s2.length(), s1.length()); } });
- 对 ArrayList 进行排序:
-
反转元素顺序:
List<String> fruits = Arrays.asList("Apple", "Banana", "Cherry"); Collections.reverse(fruits);
-
随机打乱集合元素顺序:
List<Integer> shuffledNumbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); Collections.shuffle(shuffledNumbers);
-
查找元素:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); int index = Collections.binarySearch(list, 3); // 返回索引值,若不存在返回负数
-
填充集合:
List<Integer> filledList = Collections.nCopies(10, 0); // 创建包含10个0的列表
-
同步控制:
List<String> unsynchronizedList = new ArrayList<>(); List<String> synchronizedList = Collections.synchronizedList(unsynchronizedList);
上述代码创建了一个线程安全的 List,可以在多线程环境中安全地访问。
-
最大/最小元素:
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5); int max = Collections.max(integers); int min = Collections.min(integers);
-
替换所有满足条件的元素:
List<String> strings = Arrays.asList("A", "B", "C", "D"); Collections.replaceAll(strings, "B", "X");
以上只是 Collections
类的部分功能示例,实际上还有很多其他方法,包括并集、交集、差集的操作等,它们可以帮助开发者更高效地处理和管理集合对象。
顺便Arrays的使用
java.util.Arrays
是 Java 中一个非常实用的工具类,它提供了大量的静态方法来操作数组,包括排序、搜索、填充、转换以及比较等。以下是一些 Arrays
类的典型用法:
-
数组转字符串:
int[] numbers = {1, 2, 3, 4, 5}; String strNumbers = Arrays.toString(numbers); System.out.println(strNumbers); // 输出 "[1, 2, 3, 4, 5]"
-
数组排序:
int[] unsortedArray = {5, 2, 9, 1, 7}; Arrays.sort(unsortedArray); for (int num : unsortedArray) { System.out.print(num + " "); // 输出 "1 2 5 7 9" } // 对于对象数组(假设是实现了Comparable接口的自定义类实例数组) Person[] people = ...; Arrays.sort(people); // 自然排序 // 或者提供Comparator进行定制排序: Arrays.sort(people, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { return p1.getName().compareTo(p2.getName()); } });
-
数组填充:
int[] array = new int[5]; Arrays.fill(array, 0); // 所有元素都填充为0
-
数组复制:
int[] source = {1, 2, 3}; int[] destination = new int[source.length]; System.arraycopy(source, 0, destination, 0, source.length); // 或使用 Arrays.copyOf 方法简化: destination = Arrays.copyOf(source, source.length);
-
数组二分查找:
int[] sortedArray = {1, 3, 5, 7, 9}; int searchValue = 5; int index = Arrays.binarySearch(sortedArray, searchValue); if (index >= 0) { System.out.println("Found at index: " + index); } else { System.out.println(searchValue + " not found in the array."); }
-
数组是否相等:
int[] array1 = {1, 2, 3}; int[] array2 = {1, 2, 3}; boolean areEqual = Arrays.equals(array1, array2); // 输出 true
-
将数组转换为 List:
Integer[] integers = {1, 2, 3}; List<Integer> list = new ArrayList<>(Arrays.asList(integers));
请注意,Arrays.asList()
返回的列表对于基本类型数组(如 int[]
)不会自动装箱为包装类型数组(如 Integer[]
),因此对于基本类型数组无法直接转换成 List 集合。如果需要将基本类型的数组转换为 List,通常需要手动遍历并添加到 List 中。
以上示例展示了 Arrays
类中的一些常见用法,但实际功能远不止于此。通过该类提供的静态方法,可以更方便地处理和操作数组。
集合在Android开发中的使用
在Android开发中,集合类被广泛应用于多种场景,以下是常见的一些使用场景:
-
数据存储:
- ArrayList:用于存储和管理可重复的数据项列表,例如用户列表、消息列表等。由于其基于数组实现,支持随机访问(通过索引),所以当需要频繁按索引进行查找或更新元素时,ArrayList 是一个很好的选择。
ArrayList<User> userList = new ArrayList<>(); userList.add(new User("Alice")); userList.add(new User("Bob"));
-
数据缓存:
- HashMap 或 SparseArray(针对整型键优化):用于存储键值对数据,如网络请求返回的JSON对象转换后的数据结构,或者本地缓存的数据。
HashMap<String, String> userMap = new HashMap<>(); userMap.put("id", "123"); userMap.put("name", "Alice"); // 对于整数键,使用 SparseArray 可以更高效地存储 SparseArray<User> sparseUserMap = new SparseArray<>(); sparseUserMap.put(123, new User("Alice"));
-
多重条件筛选与排序:
- HashSet:用来存储不包含重复元素的集合,适合用于去除重复项、判断唯一性等情况。
HashSet<Integer> uniqueIds = new HashSet<>(); uniqueIds.add(1); uniqueIds.add(2); uniqueIds.add(1); // 重复添加会被忽略
-
数据处理与遍历:
- 在Adapter中,集合类常作为数据源,结合ListView、RecyclerView等视图组件展示数据。
- 使用迭代器或流式API遍历集合,进行数据处理和过滤操作。
List<String> messages = ...; for (String message : messages) { // 遍历并处理每条消息 } // 或者使用 Java 8+ 的 Stream API messages.stream() .filter(message -> !message.isEmpty()) .forEach(System.out::println);
-
数据结构转换:
- 将数据库查询结果转换为List、Set或其他集合形式以便进一步处理和显示。
-
后台任务与线程安全:
- 使用
Collections.synchronizedList
或CopyOnWriteArrayList
等线程安全的集合类来确保多线程环境下数据的安全访问。
- 使用
-
Android特有场景:
- 在性能敏感的场景下,
ArrayMap
和SparseArray
被设计为替代传统的 HashMap 和 ArrayList,因为它们在内存占用和性能上做了优化,更适合Android应用中的特定需求。例如,SparseArray不需要装箱操作,对于大量整数键值对更加高效。
- 在性能敏感的场景下,
集合在Android开发中扮演了关键角色,从数据持久化、界面渲染到后台逻辑处理等多个环节都离不开集合类的使用。