1. 集合框架概述
Java 集合框架提供了一套用于存储和管理对象的标准接口和实现类。它简化了开发过程,提高了代码的可读性和可维护性。
集合框架的核心概念:
- 接口 (Interface): 定义集合类的通用行为,例如添加元素、删除元素、遍历元素等。
- 实现类 (Implementation): 提供对接口的具体实现,例如 ArrayList、HashSet、HashMap 等。
- 迭代器 (Iterator): 用于遍历集合元素,提供了一种标准方式。
集合框架的主要优势:
- 代码复用: 提供了统一的接口,可以方便地使用不同的集合类。
- 类型安全: 泛型机制保证了集合中元素类型的安全。
- 高效性: 提供了各种高效的实现,满足不同场景的需求。
- 可扩展性: 可以根据需要创建新的集合类。
2. 集合接口
Java 集合框架中定义了几个主要的接口,这些接口定义了集合类的基本操作。
2.1 Collection 接口
Collection
是所有集合类的根接口,定义了集合类的基本操作,例如添加、删除、清空、判断大小等。
常用方法:
add(E e)
: 添加元素到集合中。Collection<String> collection = new ArrayList<>(); collection.add("Apple");
remove(Object o)
: 从集合中删除元素。collection.remove("Apple");
contains(Object o)
: 判断集合中是否包含指定元素。boolean containsApple = collection.contains("Apple");
size()
: 返回集合的大小。int size = collection.size();
isEmpty()
: 判断集合是否为空。boolean isEmpty = collection.isEmpty();
iterator()
: 返回迭代器,用于遍历集合元素。Iterator<String> iterator = collection.iterator();
2.2 List 接口
List
接口继承自 Collection
接口,它表示有序的集合,允许重复元素。
常用方法:
get(int index)
: 获取指定索引位置的元素。String element = list.get(1);
set(int index, E element)
: 将指定索引位置的元素替换为新的元素。list.set(1, "Banana");
add(int index, E element)
: 在指定索引位置插入元素。list.add(1, "Orange");
remove(int index)
: 删除指定索引位置的元素。list.remove(1);
indexOf(Object o)
: 返回指定元素在列表中的第一个索引位置。int index = list.indexOf("Banana");
2.3 Set 接口
Set
接口继承自 Collection
接口,它表示无序的集合,不允许重复元素。
常用方法:
add(E e)
: 添加元素到集合中,如果元素已存在,则不添加。Set<String> set = new HashSet<>(); boolean added = set.add("Apple");
2.4 Map 接口
Map
接口不继承自 Collection
接口,它表示键值对的映射关系,键不能重复,值可以重复。
常用方法:
put(K key, V value)
: 将键值对添加到映射关系中。map.put("Apple", 1);
get(Object key)
: 获取指定键对应的值。int value = map.get("Apple");
remove(Object key)
: 删除指定键的键值对。map.remove("Apple");
containsKey(Object key)
: 判断映射关系中是否包含指定键。boolean containsKey = map.containsKey("Apple");
containsValue(Object value)
: 判断映射关系中是否包含指定值。boolean containsValue = map.containsValue(1);
3. 集合的常用操作
Java 集合框架提供了多种操作集合的方法,包括添加元素、删除元素、遍历元素、判断集合大小以及判断集合是否为空。以下是对这些常用操作的详细说明和示例代码。
3.1 添加元素
使用 add()
方法可以将元素添加到集合中。对于 List
接口的实现类,元素将按添加的顺序排列;对于 Set
接口的实现类,不允许重复元素。
示例代码:
// 创建一个 ArrayList 集合
List<String> list = new ArrayList<>();
// 添加元素
list.add("Java");
list.add("Python");
list.add("C++");
System.out.println("集合中的元素:" + list);
输出结果:
集合中的元素:[Java, Python, C++]
3.2 删除元素
使用 remove()
方法可以删除指定的元素。对于 List
接口的实现类,可以根据索引位置或元素值删除;对于 Set
接口的实现类,只能根据元素值删除。
示例代码:
// 删除元素
list.remove("Python");
System.out.println("集合中的元素:" + list);
输出结果:
集合中的元素:[Java, C++]
3.3 遍历元素
使用迭代器或增强型 for
循环可以遍历集合中的元素。
示例代码:
// 遍历元素
for (String language : list) {
System.out.println(language);
}
// 使用迭代器遍历元素
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
输出结果:
Java
C++
Java
C++
3.4 判断大小
使用 size()
方法可以获取集合的大小,即集合中包含的元素数量。
示例代码:
System.out.println("集合的大小:" + list.size());
输出结果:
集合的大小:2
3.5 判断是否为空
使用 isEmpty()
方法可以判断集合是否为空。如果集合为空,该方法返回 true
;否则返回 false
。
示例代码:
System.out.println("集合是否为空:" + list.isEmpty());
输出结果:
集合是否为空:false
4. 迭代器
迭代器 (Iterator) 是 Java 集合框架中的一个重要概念,它提供了一种遍历集合元素的标准方式,而无需关心集合的具体实现。
4.1 迭代器的作用
- 提供标准的遍历方式: 迭代器统一了遍历不同集合类的接口,无论集合是
ArrayList
、LinkedList
还是HashSet
,都可以使用相同的Iterator
接口进行遍历。 - 隐藏集合实现细节: 使用迭代器可以屏蔽集合内部的实现细节,用户只需要关注如何迭代元素,而无需关心元素是如何存储和管理的。
- 支持元素的删除: 迭代器提供
remove()
方法,可以在遍历过程中删除元素。
4.2 迭代器的使用
使用迭代器遍历集合的步骤如下:
- 获取迭代器: 通过调用集合的
iterator()
方法获取迭代器对象。 - 循环遍历: 使用
hasNext()
方法判断是否还有下一个元素,如果还有则调用next()
方法获取下一个元素。 - 删除元素: 调用
remove()
方法删除当前元素。
示例代码:
import java.util.ArrayList;
import java.util.Iterator;
public class IteratorExample {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
// 获取迭代器
Iterator<String> iterator = list.iterator();
// 循环遍历
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println(fruit);
// 删除元素
if (fruit.equals("Banana")) {
iterator.remove();
}
}
// 输出修改后的集合
System.out.println(list);
}
}
输出结果:
Apple
Banana
Cherry
[Apple, Cherry]
4.3 迭代器与增强 for 循环
Java 中的增强 for 循环 (for-each 循环) 也能够方便地遍历集合,其底层实际上就是使用迭代器实现的。
for (String fruit : list) {
System.out.println(fruit);
}
4.4 迭代器的注意事项
- 迭代器只能单向遍历,不能向后移动。
- 在使用迭代器遍历集合时,不要直接修改集合,否则会导致迭代器失效。
- 如果需要在遍历过程中删除元素,只能使用
iterator.remove()
方法,不能直接调用集合的remove()
方法。
5. 泛型概述
泛型是 Java 中的一种机制,它允许编写与类型无关的代码,从而提高代码的可重用性和安全性。通过使用泛型,我们可以编写能够处理各种数据类型的代码,而无需显式地指定数据类型。
泛型带来的优势:
- 类型安全: 泛型可以帮助我们避免类型转换错误,因为编译器会进行类型检查。
- 代码可重用: 泛型可以让我们编写一次代码,然后在不同的数据类型上重复使用。
- 提高可读性: 泛型代码更易于理解,因为它明确地指定了数据类型。
泛型使用符号:
<T>
: 表示一个类型参数,T 可以是任何类型。E
: 表示元素类型,通常用于集合。K
: 表示键类型,通常用于 Map。V
: 表示值类型,通常用于 Map。
6. 泛型类
泛型类是带有类型参数的类。我们可以在类的声明中使用类型参数,然后在类的定义中使用这些参数来代替具体的类型。
示例代码:
// 定义泛型类 GenericBox,<T> 表示类型参数
public class GenericBox<T> {
// 私有变量,存储内容
private T content;
// 设置内容
public void setContent(T content) {
this.content = content;
}
// 获取内容
public T getContent() {
return content;
}
public static void main(String[] args) {
// 创建 GenericBox<String> 实例并设置内容
GenericBox<String> stringBox = new GenericBox<>();
stringBox.setContent("Hello");
System.out.println(stringBox.getContent());
// 创建 GenericBox<Integer> 实例并设置内容
GenericBox<Integer> integerBox = new GenericBox<>();
integerBox.setContent(123);
System.out.println(integerBox.getContent());
}
}
输出结果:
Hello
123
7. 泛型方法
泛型方法是在方法定义中引入类型参数。这些类型参数可以用于方法的参数列表和返回类型。
示例代码:
public class GenericMethodExample {
// 泛型方法
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4, 5};
String[] stringArray = {"A", "B", "C", "D"};
// 调用泛型方法
printArray(intArray);
printArray(stringArray);
}
}
输出结果:
1 2 3 4 5
A B C D
8. 泛型边界
泛型边界允许我们限制类型参数的范围。我们可以使用 extends
关键字来指定上界,或者使用 super
关键字来指定下界。
8.1 上界通配符
上界通配符使用 extends
关键字,可以接受该类型及其子类型。
示例代码:
public static void printList(List<? extends Number> list) {
for (Number n : list) {
System.out.println(n);
}
}
8.2 下界通配符
下界通配符使用 super
关键字,可以接受该类型及其父类型。
示例代码:
public static void addNumber(List<? super Integer> list) {
list.add(1);
list.add(2);
}
9. 泛型接口
泛型接口是带有类型参数的接口。我们可以在接口的声明中使用类型参数,然后在接口的定义中使用这些参数来代替具体的类型。
示例代码:
public interface GenericInterface<T> {
void doSomething(T t);
}
public class GenericInterfaceImpl implements GenericInterface<String> {
@Override
public void doSomething(String s) {
System.out.println(s);
}
public static void main(String[] args) {
GenericInterface<String> generic = new GenericInterfaceImpl();
generic.doSomething("Hello");
}
}
输出结果:
Hello
10. 常用集合类
Java 集合框架中包含了许多常用的集合类,每个集合类都有其特定的用途和特点。
10.1 List 接口实现类
List 接口代表有序的集合,元素可以重复出现。
10.1.1 ArrayList
ArrayList
是一个动态数组,它的底层实现是一个可变大小的数组。ArrayList
提供了快速的随机访问能力,但在插入和删除元素时,可能需要移动大量元素。
适用场景: 适用于需要频繁读取元素,而插入和删除操作较少的场景。
示例代码:
List<String> arrayList = new ArrayList<>();
arrayList.add("Apple");
arrayList.add("Banana");
arrayList.add("Cherry");
System.out.println(arrayList);
输出结果:
[Apple, Banana, Cherry]
10.1.2 LinkedList
LinkedList
是一个双向链表,它的底层实现是一个链表结构。LinkedList
在插入和删除元素时性能较好,但随机访问元素的性能较差。
适用场景: 适用于需要频繁插入和删除元素,而读取操作较少的场景。
示例代码:
List<String> linkedList = new LinkedList<>();
linkedList.add("Apple");
linkedList.add("Banana");
linkedList.add("Cherry");
System.out.println(linkedList);
输出结果:
[Apple, Banana, Cherry]
10.2 Set 接口实现类
Set 接口代表无序的集合,元素不能重复出现。
10.2.1 HashSet
HashSet
是一个基于哈希表实现的集合,它不保证集合的迭代顺序,并且不允许重复元素。
适用场景: 适用于需要快速判断元素是否存在,且不关心元素顺序的场景。
示例代码:
Set<String> hashSet = new HashSet<>();
hashSet.add("Apple");
hashSet.add("Banana");
hashSet.add("Cherry");
System.out.println(hashSet);
输出结果:
[Banana, Apple, Cherry]
10.2.2 TreeSet
TreeSet
是一个基于红黑树实现的集合,它保证集合的迭代顺序,并且不允许重复元素。
适用场景: 适用于需要有序集合的场景。
示例代码:
Set<String> treeSet = new TreeSet<>();
treeSet.add("Apple");
treeSet.add("Banana");
treeSet.add("Cherry");
System.out.println(treeSet);
输出结果:
[Apple, Banana, Cherry]
10.3 Map 接口实现类
Map 接口代表键值对集合,每个键对应一个值。
10.3.1 HashMap
HashMap
是一个基于哈希表实现的映射关系,它不保证键值对的迭代顺序,并且允许键为 null
。
适用场景: 适用于需要快速访问键值对,且不关心键值对顺序的场景。
示例代码:
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("Apple", 1);
hashMap.put("Banana", 2);
hashMap.put("Cherry", 3);
System.out.println(hashMap);
输出结果:
{Apple=1, Banana=2, Cherry=3}
10.3.2 TreeMap
TreeMap
是一个基于红黑树实现的映射关系,它保证键值对的迭代顺序,并且不允许键为 null
。
适用场景: 适用于需要有序键值对的场景。
示例代码:
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Apple", 1);
treeMap.put("Banana", 2);
treeMap.put("Cherry", 3);
System.out.println(treeMap);
输出结果:
{Apple=1, Banana=2, Cherry=3}