一、集合概述
Java 集合是一套用于管理多个对象的工具类集合,提供了存储、检索、添加、删除、排序、遍历等高效操作,弥补了数组的局限性(数组长度固定、仅支持简单的元素访问)。
Java 集合框架主要分为两大体系,由顶层接口定义:
| 体系 | 核心接口 | 存储特点 | 典型实现类 |
|---|---|---|---|
| 单个元素存储 | Collection |
存储一组独立的元素 | List、Set、Queue |
| 键值对存储 | Map |
存储键(Key)值(Value)映射 | HashMap、TreeMap |
其中 Collection 是单个元素集合的根接口,Map 是键值对集合的根接口,二者无继承关系。
集合 vs 数组
| 特性 | 数组 | 集合 |
|---|---|---|
| 长度 | 固定,初始化时指定 | 动态可变 |
| 存储类型 | 基本类型 / 引用类型均可 | 仅引用类型(基本类型需包装) |
| 操作方法 | 需手动实现(如扩容、排序) | 内置丰富的操作方法 |
| 效率 | 访问速度快(直接索引) | 部分集合(如 ArrayList)接近数组,部分(如 LinkedList)增删更快 |
二、Collection接口
Collection 是 Java 集合框架中所有单个元素集合的顶级接口 ,定义了一组通用的操作方法,其子接口(List、Set、Queue)都继承并实现了这些方法,保证了集合操作的统一性。
Collection 作为根接口,为所有单列集合提供了通用的行为规范 ,它本身不能直接实例化,需通过其子接口的实现类(如 ArrayList、HashSet)来使用。
Collection 接口定义了一系列通用方法,适用于所有单列集合,主要分为以下几类:
| 方法分类 | 核心方法 | 功能说明 |
|---|---|---|
| 元素添加 | boolean add(E e) |
向集合中添加一个元素,成功返回 true |
boolean addAll(Collection<? extends E> c) |
将另一个集合的所有元素添加到当前集合,成功返回 true |
|
| 元素删除 | boolean remove(Object o) |
从集合中移除指定元素,成功返回 true |
boolean removeAll(Collection<?> c) |
移除当前集合中与指定集合共有的所有元素(求差集) | |
void clear() |
清空集合中所有元素 | |
| 元素查询 | int size() |
返回集合中元素的个数 |
boolean isEmpty() |
判断集合是否为空(元素个数为 0) | |
boolean contains(Object o) |
判断集合是否包含指定元素 | |
boolean containsAll(Collection<?> c) |
判断集合是否包含指定集合的所有元素 | |
| 迭代遍历 | Iterator<E> iterator() |
返回迭代器(Iterator)对象,用于遍历集合元素 |
| 集合转换 | Object[] toArray() |
将集合转换为 Object 类型数组 |
<T> T[] toArray(T[] a) |
将集合转换为指定类型的数组 | |
| 其他 | boolean retainAll(Collection<?> c) |
保留当前集合中与指定集合共有的元素(求交集),其余元素移除 |
三、List接口
继 Collection 接口之后,List 是 Java 集合框架中单列集合的重要子接口,也是开发中最常用的集合类型之一。
1.List接口简介
List 是 Collection 接口的子接口,专门用于存储有序、可重复 的元素集合,其核心特征是为每个元素分配了索引 (从 0 开始),支持通过索引直接访问元素,这也是它与 Set 接口最核心的区别。
核心特性:
- 有序性:元素的存储顺序与添加顺序一致,遍历结果与添加顺序相同。
- 可重复性 :允许存储多个相同的元素(包括
null)。 - 索引访问 :支持通过索引(
int index)对元素进行增删改查,类似数组的访问方式。
List 接口在 Collection 通用方法的基础上,新增了一系列基于索引的操作方法,这是其核心特色:
| 方法签名 | 功能说明 |
|---|---|
E get(int index) |
获取指定索引位置的元素 |
E set(int index, E element) |
替换指定索引位置的元素,返回被替换的旧元素 |
void add(int index, E element) |
在指定索引位置插入元素,后续元素后移 |
E remove(int index) |
删除指定索引位置的元素,返回被删除的元素 |
int indexOf(Object o) |
返回指定元素在集合中首次出现的索引,不存在则返回 -1 |
int lastIndexOf(Object o) |
返回指定元素在集合中最后出现的索引,不存在则返回 -1 |
List<E> subList(int fromIndex, int toIndex) |
获取从 fromIndex(包含)到 toIndex(不包含)的子集合 |
2.ArrayList集合
ArrayList 是 List 接口最常用的实现类,底层基于动态扩容的数组实现,兼顾了数组的快速访问特性和集合的动态扩容能力。
java
import java.util.ArrayList;
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("张三");
list.add("李四");
list.add("王五");
list.add("赵六");
// 获取集合中元素的个数
System.out.println("集合长度:" + list.size());
// 取出并打印指定位置的元素
System.out.println("第2个元素为:" + list.get(1));
}
}

3.LinkedList集合
LinkedList 是 List 接口的另一个重要实现类,底层基于双向链表 实现,同时还实现了 Deque 接口(双端队列),支持队列、栈的操作。
核心特性
- 底层结构:双向链表(每个节点包含前驱节点、后继节点引用,以及当前元素值)。
- 扩容机制:无需提前分配容量,添加元素时只需创建新节点并修改链表引用,无扩容开销。
java
import java.util.LinkedList;
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
// 添加元素
linkedList.add("A");
linkedList.addFirst("B"); // 添加到链表头部
linkedList.addLast("C"); // 添加到链表尾部
System.out.println(linkedList); // 输出:[B, A, C]
// 访问首尾元素
System.out.println(linkedList.getFirst()); // 输出:B
System.out.println(linkedList.getLast()); // 输出:C
// 删除首尾元素
linkedList.removeFirst();
System.out.println(linkedList); // 输出:[A, C]
}
}

4.Iterator接口
Iterator(迭代器)是 Java 集合框架中用于遍历集合元素的标准接口 ,定义了遍历集合的通用方法,所有实现了 Collection 接口的集合(包括 List)都可通过 iterator() 方法获取迭代器对象。迭代器提供了一种统一的遍历方式,无需关心集合的底层实现(数组 / 链表),同时支持在遍历过程中安全删除元素。
核心方法:
| 方法签名 | 功能说明 |
|---|---|
boolean hasNext() |
判断集合中是否还有未遍历的元素 |
E next() |
获取下一个元素(调用前需先通过 hasNext() 判断,否则会抛出 NoSuchElementException) |
void remove() |
删除最近一次通过 next() 获取的元素(可选操作,用于遍历中安全删除元素) |
java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
// 获取迭代器
Iterator<String> it = list.iterator();
// 遍历元素
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
// 遍历中删除指定元素(安全方式)
if (s.equals("Python")) {
it.remove();
}
}
System.out.println(list); // 输出:[Java, C++]
}
}

注意事项
- 并发修改异常 :遍历过程中,若直接调用集合的
add()/remove()方法(而非迭代器的remove()),会触发ConcurrentModificationException,因为迭代器会检测集合的修改次数是否与预期一致。 - 迭代器单向遍历 :
Iterator只能从前往后遍历,不支持反向遍历(若需反向遍历,可使用ListIterator,List接口特有的迭代器)。
5.foreach循环
foreach 循环(增强 for 循环)是 JDK 5 引入的语法糖 ,底层基于 Iterator 实现,提供了更简洁的遍历语法,适用于仅读取元素的场景。
核心特点:
- 语法简洁:无需手动获取迭代器,直接遍历集合元素。
- 只读遍历 :不支持在遍历过程中修改集合(添加 / 删除元素),否则同样会抛出
ConcurrentModificationException。 - 适用范围 :可遍历所有实现了
Iterable接口的集合(包括List、Set),也可遍历数组。
java
import java.util.ArrayList;
import java.util.List;
public class ForeachDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
// foreach 循环遍历 List
for (String s : list) {
System.out.println(s);
}
// foreach 遍历数组(扩展)
int[] arr = {1, 2, 3};
for (int num : arr) {
System.out.println(num);
}
}
}

四、Set接口
在 Java 集合框架中,Set 是 Collection 接口的重要子接口,与 List 形成互补,专注于无序、不可重复的元素存储。
1.Set接口简介
Set 是 Collection 接口的子接口,定义了无序、不可重复的单列集合规范,是处理唯一元素集合的核心接口。
核心特性:
- 不可重复性 :集合中不允许存在重复元素(判断依据是
equals()方法返回false且hashCode()返回值不同,二者结合保证元素唯一性)。 - 无序性 :元素的存储顺序与添加顺序无关(底层基于哈希表 / 红黑树实现,并非按插入顺序保存),且无索引,无法通过索引访问元素。
- 继承通用方法 :完全继承
Collection接口的方法,无额外扩展方法(因为索引操作对无序集合无意义)。
2.HashSet集合
HashSet 是 Set 接口最常用的实现类,底层基于 HashMap 实现(利用 HashMap 的键存储元素,值为固定的 PRESENT 对象),是处理唯一元素的首选集合。
java
import java.util.HashSet;
import java.util.Set;
public class HashSetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
// 添加元素(重复元素不会被存储)
set.add("Java");
set.add("Python");
set.add("Java"); // 重复元素,添加失败
System.out.println(set); // 输出:[Java, Python](顺序可能不同)
// 删除元素
set.remove("Python");
System.out.println(set); // 输出:[Java]
// 遍历(无索引,使用迭代器或 foreach)
for (String s : set) {
System.out.println(s);
}
}
}

java
import java.util.*;
class Student {
private String id;
private String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
//重写toString()方法
public String toString() {
return id + ":" + name;
}
//重写hashCode方法
public int hashCode() {
return id.hashCode();
}
// 重写equals方法
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (! (obj instanceof Student)) {
return false;
}
Student stu = (Student) obj;
boolean b = this.id.equals(stu.id);
return b;
}
}
public class Example09 {
public static void main(String[] args) {
HashSet hs = new HashSet();
Student s1 = new Student("1001", "张三");
Student s2 = new Student("1002", "李四");
Student s3 = new Student("1002", "李四");
hs.add(s1);
hs.add(s2);
hs.add(s3);
System.out.println(hs);
}
}

注意事项:若自定义类作为 HashSet 的元素,必须重写 hashCode() 和 equals() 方法,否则无法保证元素唯一性(默认使用 Object 类的方法,基于对象地址判断,会导致相同内容的对象被视为不同元素)。
3.TreeMap集合
TreeMap 是 Map 接口的实现类,底层基于红黑树 实现,用于存储有序的键值对,键具有唯一性且可排序。
java
import java.util.TreeMap;
import java.util.Map;
public class TreeMapDemo {
public static void main(String[] args) {
Map<Integer, String> treeMap = new TreeMap<>();
// 添加键值对
treeMap.put(3, "C");
treeMap.put(1, "A");
treeMap.put(2, "B");
// 遍历(按键的自然顺序排序)
for (Map.Entry<Integer, String> entry : treeMap.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
// 输出:1:A 2:B 3:C
}
}

4.Properties集合
Properties 是 Hashtable<Object, Object> 的子类,属于 Map 接口的实现类,专门用于处理配置文件 (如 .properties 文件),键和值均为 String 类型。
核心方法:
| 方法签名 | 功能说明 |
|---|---|
String getProperty(String key) |
根据键获取值,若键不存在返回 null |
String getProperty(String key, String defaultValue) |
根据键获取值,若键不存在返回默认值 |
Object setProperty(String key, String value) |
设置键值对(等同于 put() 方法) |
void load(InputStream inStream) |
从字节输入流中读取 .properties 文件的内容到集合中 |
void store(OutputStream out, String comments) |
将集合中的键值对写入字节输出流(保存为 .properties 文件) |
java
import java.util.*;
public class Example21 {
public static void main(String[] args) {
Properties p = new Properties(); // 创建Properties对象
p.setProperty("BackgroundColor", "red");
p.setProperty("FontSize", "14px");
p.setProperty("Language", "chinese");
Enumeration names = p.propertyNames(); // 获取所有属性名
while (names.hasMoreElements()) {
String key = (String) names.nextElement(); // 遍历所有属性名
String value = p.getProperty(key); // 根据属性名获取属性值
System.out.println(key + " = " + value); // 输出属性名和属性值
}
}
}

五、Map接口
在 Java 集合框架中,Map 是与 Collection 并列的顶级接口,专注于键值对(Key-Value) 的存储与操作,是开发中处理映射关系数据的核心工具。
1.Map接口简介
Map 是 Java 集合框架中存储键值对的顶级接口 ,定义了一组通过键(Key)访问值(Value)的规范,其核心是键的唯一性 和键与值的一一映射关系。
核心特性:
- 键值对存储:每个元素由一个键(Key)和一个值(Value)组成,键是唯一的,值可以重复。
- 无序性(默认) :大部分实现类(如
HashMap)中,元素的存储顺序与添加顺序无关(LinkedHashMap除外)。 - 无索引:无法通过索引访问元素,只能通过键来获取对应的值。
- 键值类型 :支持泛型,可指定键和值的类型(如
Map<String, Integer>),避免类型转换异常。
核心方法
Map 接口定义了操作键值对的通用方法,主要分为以下几类:
| 方法分类 | 核心方法 | 功能说明 |
|---|---|---|
| 元素添加 | V put(K key, V value) |
向集合中添加键值对,若键已存在,则替换对应的值并返回旧值;若键不存在,返回 null |
| 元素添加 | void putAll(Map<? extends K, ? extends V> m) |
将另一个 Map 的所有键值对添加到当前 Map 中 |
| 元素删除 | V remove(Object key) |
根据键删除对应的键值对,返回被删除的值;若键不存在,返回 null |
| 元素删除 | void clear() |
清空 Map 中所有键值对 |
| 元素查询 | V get(Object key) |
根据键获取对应的值;若键不存在,返回 null |
| 元素查询 | int size() |
返回 Map 中键值对的个数 |
| 元素查询 | boolean isEmpty() |
判断 Map 是否为空(键值对个数为 0) |
| 元素查询 | boolean containsKey(Object key) |
判断 Map 是否包含指定的键 |
| 元素查询 | boolean containsValue(Object value) |
判断 Map 是否包含指定的值 |
| 集合视图 | Set<K> keySet() |
返回所有键组成的 Set 集合(键的唯一性对应 Set 的特性) |
| 集合视图 | Collection<V> values() |
返回所有值组成的 Collection 集合 |
| 集合视图 | Set<Map.Entry<K, V>> entrySet() |
返回所有键值对(Map.Entry 对象)组成的 Set 集合,用于遍历 Map |
2.HashMap集合
HashMap 是 Map 接口最常用的实现类,底层基于哈希表(数组 + 链表 / 红黑树) 实现,是处理键值对映射的首选集合。
java
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapDemo {
public static void main(String[] args) {
// 创建 HashMap,指定键为 String 类型,值为 Integer 类型
Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("Java", 90);
map.put("Python", 85);
map.put("Java", 95); // 键重复,替换值
// 根据键获取值
System.out.println(map.get("Java")); // 输出:95
// 遍历方式1:遍历所有键,再通过键获取值
Set<String> keys = map.keySet();
for (String key : keys) {
System.out.println(key + ":" + map.get(key));
}
// 遍历方式2:遍历键值对(推荐,效率更高)
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
// 删除键值对
map.remove("Python");
System.out.println(map); // 输出:{Java=95}
}
}

注意事项
- 若自定义类作为
HashMap的键,必须重写hashCode()和equals()方法,否则无法保证键的唯一性。 - 避免使用可变对象作为键(如
ArrayList),否则对象内容修改后,哈希值会变化,导致无法正确获取对应的值。
3.TreeMap集合
TreeMap 是 Map 接口的有序实现类,底层基于红黑树(自平衡的二叉查找树) 实现,专注于按键排序的键值对存储。
java
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
// 1. 自然排序(键为 Integer,默认按升序排列)
Map<Integer, String> treeMap1 = new TreeMap<>();
treeMap1.put(3, "C");
treeMap1.put(1, "A");
treeMap1.put(2, "B");
System.out.println(treeMap1); // 输出:{1=A, 2=B, 3=C}
// 2. 定制排序(键为 String,按字符串长度降序排列)
Map<String, Integer> treeMap2 = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s2.length() - s1.length(); // 降序
}
});
treeMap2.put("Java", 90);
treeMap2.put("Python", 85);
treeMap2.put("C", 95);
System.out.println(treeMap2); // 输出:{Python=85, Java=90, C=95}
}
}
4.Properties集合
Properties 是 Hashtable<Object, Object> 的子类,属于 Map 接口的特化实现类,专门用于处理配置文件(如 .properties 文件) ,键和值均为 String 类型。
java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
// 1. 创建 Properties 集合
Properties prop = new Properties();
// 2. 设置键值对
prop.setProperty("username", "admin");
prop.setProperty("password", "123456");
prop.setProperty("port", "8080");
// 3. 写入到 .properties 配置文件
prop.store(new FileOutputStream("config.properties"), "System Config");
// 4. 从配置文件读取内容
Properties prop2 = new Properties();
prop2.load(new FileInputStream("config.properties"));
// 5. 获取配置值
System.out.println("用户名:" + prop2.getProperty("username")); // 输出:用户名:admin
System.out.println("端口:" + prop2.getProperty("port", "80")); // 输出:端口:8080
}
}
六、泛型
泛型是 Java 5 引入的核心特性之一,它解决了集合等容器类的类型安全问题,消除了大量的类型转换代码,提升了代码的可读性和可维护性。
1.泛型概述
定义:泛型(Generic)本质是参数化类型,即允许在定义类、接口、方法时,将类型作为参数来传递,使用时再指定具体的类型。就像方法的形参是值的占位符,泛型的类型参数是类型的占位符。
泛型的核心优势
- 编译时类型检查:编译器会在编译阶段检查类型是否匹配,避免运行时类型转换异常。
- 消除强制类型转换:使用时指定类型,取出元素时无需手动转换,代码更简洁。
- 代码复用:通过类型参数,可编写通用的类、方法,适配不同类型的需求。
泛型的本质:泛型是编译时的语法糖 ,JVM 在运行时并不识别泛型的类型参数(即类型擦除 ),编译后会将泛型类型擦除为原始类型(如 List<String> 擦除为 List),并在必要时插入类型转换代码。这意味着泛型仅在编译阶段起作用,目的是为了编译器的类型检查。
2.泛型类和泛型对象
泛型类是在类的定义中引入类型参数的类,语法格式为:
java
修饰符 class 类名<类型参数列表> {
// 类的成员变量、方法等可使用类型参数
}
类型参数:通常用单个大写字母表示,常用的约定:
E:Element(元素,用于集合)T:Type(类型)K:Key(键)V:Value(值)N:Number(数字)
自定义泛型类:
java
// 定义泛型类,T 为类型参数
public class GenericClass<T> {
// 成员变量使用类型参数
private T data;
// 构造方法使用类型参数
public GenericClass(T data) {
this.data = data;
}
// 方法的返回值和参数使用类型参数
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
创建泛型类的对象时,需要指定具体的类型实参,语法格式为:
java
类名<具体类型> 对象名 = new 类名<具体类型>();
创建泛型对象:
java
public class GenericClassDemo {
public static void main(String[] args) {
// 指定类型为 String
GenericClass<String> strObj = new GenericClass<>("Hello Generic");
System.out.println(strObj.getData()); // 输出:Hello Generic
// 指定类型为 Integer
GenericClass<Integer> intObj = new GenericClass<>(123);
System.out.println(intObj.getData()); // 输出:123
}
}
注意事项
- 类型参数不能是基本数据类型 :只能使用引用数据类型(如
Integer而非int,String而非char)。 - 泛型类的静态成员不能使用类型参数:静态成员属于类本身,而类型参数是对象级别的,在类加载时类型参数尚未指定。
- 不能创建类型参数的数组 :如
T[] arr = new T[10]是不允许的,因为类型擦除后无法确定数组的具体类型。
3.泛型方法
泛型方法是指在方法的定义中引入类型参数的方法,它可以定义在普通类中,也可以定义在泛型类中,泛型方法的类型参数独立于类的类型参数。
语法格式为:
java
修饰符 <类型参数列表> 返回值类型 方法名(参数列表) {
// 方法体
}
java
public class GenericMethodDemo {
// 泛型方法:交换数组中两个元素的位置
public <T> void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
GenericMethodDemo demo = new GenericMethodDemo();
// 处理 String 数组
String[] strArr = {"Java", "Python", "C++"};
demo.swap(strArr, 0, 2);
System.out.println(Arrays.toString(strArr)); // 输出:[C++, Python, Java]
// 处理 Integer 数组
Integer[] intArr = {1, 2, 3};
demo.swap(intArr, 1, 2);
System.out.println(Arrays.toString(intArr)); // 输出:[1, 3, 2]
}
}
4.泛型接口
泛型接口是在接口的定义中引入类型参数的接口,语法和使用方式与泛型类类似。
泛型接口的定义语法格式为:
java
修饰符 interface 接口名<类型参数列表> {
// 抽象方法可使用类型参数
返回值类型 方法名(参数列表);
}
实现泛型接口有两种方式:
- 实现类指定具体类型:实现接口时直接指定类型参数的具体类型,成为普通类。
- 实现类保留类型参数:实现接口时仍使用类型参数,成为泛型类。
方式 1:实现类指定具体类型
java
// 实现类指定 T 为 String
public class StringProcessor implements GenericInterface<String> {
@Override
public String process(String data) {
return data.toUpperCase(); // 将字符串转为大写
}
}
// 测试
public class GenericInterfaceDemo1 {
public static void main(String[] args) {
GenericInterface<String> processor = new StringProcessor();
System.out.println(processor.process("java")); // 输出:JAVA
}
}
方式 2:实现类保留类型参数
java
// 实现类保留类型参数 T,成为泛型类
public class GenericProcessor<T> implements GenericInterface<T> {
@Override
public T process(T data) {
// 简单返回原数据
return data;
}
}
// 测试
public class GenericInterfaceDemo2 {
public static void main(String[] args) {
GenericInterface<Integer> intProcessor = new GenericProcessor<>();
System.out.println(intProcessor.process(123)); // 输出:123
}
}
5.类型通配符
类型通配符用于在使用泛型时,表示未知的类型 ,主要解决泛型类型不兼容的问题,常用的通配符有 ?、? extends 上限、? super 下限。
java
import java.util.ArrayList;
import java.util.List;
public class BoundedWildcardSuper {
// 向集合中添加整数
public static void addIntegers(List<? super Integer> list) {
list.add(1);
list.add(2);
// list.add(3.14); // 错误:Double 不是 Integer 的子类
}
public static void main(String[] args) {
List<Object> objList = new ArrayList<>();
addIntegers(objList);
System.out.println(objList); // 输出:[1, 2]
List<Number> numList = new ArrayList<>();
addIntegers(numList);
System.out.println(numList); // 输出:[1, 2]
}
}
通配符的使用
| 通配符类型 | 含义 | 适用场景 | 操作限制 |
|---|---|---|---|
? |
任意类型 | 仅读取数据 | 不能添加元素(除 null),获取为 Object |
? extends T |
T 或 T 的子类 | 只读(获取) | 不能添加元素(除 null) |
? super T |
T 或 T 的父类 | 只写(添加) | 获取元素为 Object 类型 |
七、JDK8新特性------Lambda表达式
Lambda 表达式是 JDK 8 引入的核心特性之一,它是函数式编程的重要体现,允许将一段代码(行为)作为参数传递给方法,简化了匿名内部类的编写,大幅提升了代码的简洁性和可读性。
Lambda 表达式本质是一个可传递的代码块,可以在需要时执行一次或多次。它的出现主要是为了解决传统匿名内部类代码冗余、语法繁琐的问题,尤其适用于函数式接口的实现。
Lambda 表达式的使用前提是函数式接口,这是理解 Lambda 的关键:
- 定义 :只包含一个抽象方法的接口(可以包含默认方法、静态方法、私有方法)。
- 标识 :可使用
@FunctionalInterface注解标记(可选,但推荐使用,编译器会检查是否符合函数式接口规范)。
Java 内置的 Runnable、Comparator、Consumer、Supplier 等都是函数式接口:
java
// 自定义函数式接口
@FunctionalInterface
public interface MyFunctionalInterface {
void doSomething(String str); // 唯一抽象方法
// 允许包含默认方法
default void defaultMethod() {
System.out.println("默认方法");
}
}
Lambda 的核心优势
- 代码简洁:替代冗长的匿名内部类,一行代码即可实现接口的抽象方法。
- 行为参数化:将代码作为参数传递,实现更灵活的编程逻辑。
- 提升可读性:聚焦业务逻辑,减少模板代码的干扰。