1. Collection
1.1 集合框架概述
Java 集合框架是一组实现了常见数据结构(如列表、树集和哈希表等)的类和接口,用于存储一组数据。
开发者在使用Java的集合类时,不必考虑数据结构和算法的具体实现细节,根据场景需要直接选择并使用这些集合类,调用相应的方法即可,从而提高开发效率。
例如,开发者可以创建一个基于数组结构的集合对象,然后调用该对象的add方法向集合中添加元素,或者调用该对象的get方法从集合中获取某个已添加的元素。
Java的集合中存储的都是引用类型的元素,由于引用类型变量实际上存储的是对象的“地址”,集合中实际上只存储了元素对象在堆中的地址,而并不是将对象本身存入了集合中。
Java所有的集合类都位于java.util包中,按照存储结构可以分为两大类,即单列集合和双列集合。单列集合是指集合中的元素是单个对象,双列集合是指集合中的元素以键值对(key-value pair)的形式存在。Collection是单列集合的根接口,Map是双列集合的根接口,各自还派生出一些子接口或实现类。
1.2 Collection集合体系
Collection集合体系的架构图如下图所示:
Collection接口有3个子接口:
- List接口:有序且可以重复的集合
- Set接口:无序且不可重复的集合
- Queue接口:队列集合,用来存储满足FIFO(First In First Out)原则的容器
有序和无序:指集合中的元素是否能保存元素的添加顺序。例如,将3个整型元素5、3、9添加到集合中,List集合能够保证按照5、3、9的顺序访问元素,而Set集合无法保证能按这一顺序访问。
是否可重复:指集合中是否允许有重复的元素,重复元素指的并非是同一个元素,而是指equals方法比较为true的元素。
1.3 Collection接口的主要方法
在Collection中定义了单列集合的一些通用方法,使用这些方法可以操作所有的单列集合。
1.4 add方法示例
编写代码,测试Collection的add方法。代码示意如下:
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo1 {
public static void main(String[] args) {
Collection c = new ArrayList();
System.out.println(c); // []
c.add("Tom");
c.add("Jerry");
c.add(666);
System.out.println(c); // [Tom, Jerry, 666]
}
}
1.5 contains方法
contains() 方法用于判断给定的元素是否被包含在集合中。语法如下:
boolean contains(Object o)
若包含则返回true,否则返回false。
这里需要注意的是,集合在判断元素是否被包含在集合中是根据每个元素的equals() 方法进行比较后的结果。因此,通常有必要重写 equals() 保证 contains() 方法返回合理的结果。
编写代码,测试Collection的contains方法。代码示意如下:
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo2 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(new String("hello"));
// List集合contains方法和对象的equals方法相关
boolean flag = c.contains("hello");
System.out.println("flag: " + flag); // flag: true
System.out.println("flag: " + c.contains("hell")); // flag: false
}
}
1.6 size、clear、isEmpty方法
Collection集合还有3个常用的方法:
- int size():该方法用于返回当前集合中的元素总数
- void clear():该方法用于清空当前集合
- boolean isEmpty():该方法用于判断当前集合中是否不包含任何元素
编写代码,测试Collection的size、clear和isEmpty方法。代码示意如下:
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo3 {
public static void main(String[] args) {
Collection c = new ArrayList();
System.out.println(c.isEmpty()); // true
c.add("java");
c.add("c++");
c.add("php");
c.add("c#");
c.add("python");
// isEmpty:false, size: 5
System.out.println("isEmpty:" + c.isEmpty() + ",size: " + c.size());
// 清空集合
c.clear();
// isEmpty:true, size: 0
System.out.println("isEmpty:" + c.isEmpty() + ", size: " + c.size());
}
}
1.7 addAll与containsAll 方法
如果需要将一个集合加入另一个集合,可以使用 addAll() 方法:
boolean addAll(Collection<? extends E> c)
该方法需要传入一个集合,并将该集合中的所有元素添加到当前集合中。如果此 collection 由于调用而发生更改,则返回 true。
如果希望判断当前集合是否包含给定集合中的所有元素,可以使用containsAll() 方法:
boolean containsAll(Collection<?> c)
若包含则返回 true。
编写代码,测试Collection的addAll和containsAll方法。代码示意如下:
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo4 {
public static void main(String[] args) {
Collection passedStudentList = new ArrayList(); // 考试通过的学生名单
passedStudentList.add("Alice");
passedStudentList.add("Bob");
passedStudentList.add("Lucy");
passedStudentList.add("Lily");
Collection groupAList = new ArrayList<>(); // A组学生名单
groupAList.add("Bob");
groupAList.add("Tony");
// A组学生是否都通过了考试
boolean passed = passedStudentList.containsAll(groupAList);
if (passed) {
System.out.println("A组全部通过了考试!");
} else {
System.out.println("A组没有全部通过了考试!");
}
// B组学生名单
Collection groupBList = new ArrayList<>();
groupBList.add("Tom");
groupBList.add("Jerry");
// 将B组学生名单添加到考试通过的学生名单中
passedStudentList.addAll(groupBList);
}
}
2. Iterator迭代器
2.1 迭代器概述
迭代器(Iterator)接口是Java集合框架中的一员,诞生于JDK 1.2版本,主要用于迭代访问(即遍历)Collection中的元素,因此,Iterator对象也被称为迭代器。
获取迭代器的方式是使用Collection定义的iterator方法:
迭代器Iterator是一个接口,集合在覆盖Collection的iterator()方法时提供了迭代器的具体实现。
2.2 迭代器接口的主要方法
迭代器(Iterator)接口中定义了4个方法。
最常用的方法为:
- hasNext:用于判断当前迭代中是否有更多元素
- next:返回当前迭代中的下一个元素
- remove:从集合中移除最近一次调用next方法时返回的那个元素,与next方法搭配使用
三个方法的操作示意如下图所示:
注意:
- 遍历过程中不能直接通过Collection的 remove() 方法删除集合元素,否则会抛出并发更改异常
- 在调用 迭代器的remove() 方法前必须通过迭代器的 next() 方法迭代过元素,那么删除的就是这个元素
- 调用一次next()方法后只能调用一次remove()方法
编写代码,测试Iterator的hasNext、next和remove方法。代码示意如下:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo1 {
public static void main(String[] args) {
Collection c = new ArrayList();
// 向集合中添加1到10
for (int i = 1; i <= 10; i++){
c.add(i);
}
System.out.println(c);
// 获取集合的迭代器对象
Iterator itr = c.iterator();
// 通过迭代器遍历集合
while (itr.hasNext()) {
int i = (int)itr.next();
System.out.print(i + " ");
// 通过迭代器删除集合中的元素
if (i % 2 != 0){
itr.remove();
}
}
System.out.println();
// 输出集合中的元素
System.out.println(c);
}
}
2.3 增强for循环
增强for循环是Java 1.5之后推出了一个新的特性,用于简化集合的遍历操作。语法如下:
for(元素类型 e : 集合或数组){
循环体
}
增强for循环会按照从头到尾的顺序逐个访问集合或数组中的元素,变量e的值与集合或数组中当前访问的元素的值相同。例如,使用增强for循环访问一个包含了“a”,“b”“c”三个元素的集合,第一次循环时,e的值为“a”,第二次循环时,e的值为“b”,以此类推。
增强for循环并非新的语法,而是在编译过程中,编译器会将增强for循环转换为迭代器模式。所以增强for循环本质上是迭代器。
编写代码,测试增强的for循环的使用。代码示意如下:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo2 {
public static void main(String[] args) {
Collection c = new ArrayList();
// 向集合中添加1到10
for (int i = 1; i <= 10; i++){
c.add(i);
}
// 使用增强for循环遍历集合中的元素
for(Object o : c){
System.out.print(o +" ");
}
System.out.println();
// 也可用于遍历数组
String[] array = {"Tom", "Bob", "Jerry"};
for(String s: array){
System.out.println(s);
}
}
}
3. 泛型机制
3.1 泛型概述
泛型(Generic)是Java从JDK 1.5开始引入的,可以帮助用户建立类型安全的集合。泛型的本质就是“数据类型的参数化”。可以把泛型理解为数据类型的一个占位符(形式参数),即在编写代码时将数据类型定义成参数,这些类型参数在使用或调用时传入具体的类型。
在JDK 1.5之前,为了实现参数类型的任意化,都是通过Object类型来处理的。但这种处理方式的缺点是需要进行强制类型转换,这种强制类型转换不仅使代码臃肿,还要求开发者必须在已知实际使用的参数类型的情况下才能进行,否则容易引起ClassCastException异常。
使用泛型的好处是在程序编译期间会对类型进行检查,捕捉类型不匹配错误,以免引起ClassCastException异常;在使用了泛型的集合中,遍历时不必进行强制类型转换,数据类型都是自动转换的。
泛型也经常在类、接口和方法的定义中使用,这部分内容将在后续的课程中进行讲解。
3.2 泛型示例
编写代码,测试泛型的使用。代码示意如下:
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class GenericDemo1 {
public static void main(String[] args) {
// 使用泛型指定集合中元素为Integer类型
Collection<Integer> c = new ArrayList<>();
c.add(123);
// c.add("abc"); // 编译时报错,类型不匹配
Iterator<Integer> itr = c.iterator();
while (itr.hasNext()) {
// 无需类型转换
int i = itr.next();
System.out.print(i + " ");
}
}
}
4. 总结
1、Java 集合框架是一组实现了常见数据结构(如列表、树集和哈希表等)的类和接口,用于存储一组数据
2、Java所有的集合类都位于java.util包中,按照存储结构可以分为两大类
- 单列集合 Collection
- 双列集合 Map
3、Collection 接口有以下3个子接口
- List 接口:有序且可以重复的集合
- Set 接口:无序且不可重复的集合
- Queue 接口:队列集合,用来存储满足FIFO(First In First Out)原则的容器
4、在Collection中定义了单列集合的一些通用方法
- add、contains、size、clear、isEmpty、addAll、containsAll等
5、迭代器(Iterator)接口是Java集合框架中的一员,主要用于迭代访问(即遍历)Collection 中的元素
- hasNext、next
- remove:从集合中移除最近一次调用next方法时返回的那个元素,与next方法搭配使用
6、增强for循环是Java 1.5之后推出了一个新的特性,用于简化集合的遍历操作
7、泛型(Generic)从JDK 1.5开始引入,帮助用户建立类型安全的集合