135. Java 泛型 - 无界通配符
文章目录
- 135. Java 泛型 - 无界通配符 (`?`)
- **1. 什么是无界通配符 (`?`)?**
- **2. 为什么使用无界通配符?**
- **3. 示例:使用 `?` 处理任意列表**
- **❌ 错误示例**
- **✅ 正确示例**
- **4. 为什么 `List<Object>` 和 `List<?>` 不一样?**
- **❌ 错误示例**
- **5. 适用场景**
- **6. 结论**
135. Java 泛型 - 无界通配符 (?)
在 Java 泛型中,无界通配符 (?) 允许表示任何类型,使代码更加通用。
本篇将详细讲解无界通配符的概念,并结合示例帮助理解。
1. 什么是无界通配符 (?)?
无界通配符 ? 代表“未知类型”,它可以用于泛型类或泛型方法,使其适用于任意类型。
例如:
List<?> list;
list可以接受List<String>、List<Integer>、List<Double>等任何类型的List。- 但由于
?代表未知类型,无法向list中添加元素(除了null)。
2. 为什么使用无界通配符?
无界通配符适用于以下两种情况:
- 仅使用
Object类的方法,而不需要特定类型的方法(如toString()、equals()、hashCode())。 - 方法的逻辑不依赖于泛型类型参数,如
List.size()或List.clear()。
✅ 无界通配符的语法
List<?> list = new ArrayList<String>();
- 这里
list可以引用任何类型的List(List<Integer>、List<Double>等)。 - 但是,我们不能向
list添加元素(除了null)。
3. 示例:使用 ? 处理任意列表
📌 需求:编写一个方法,能够打印任何类型的 List,包括 List<String>、List<Integer>、List<Double> 等。
❌ 错误示例
以下代码无法打印 List<Integer>,因为 List<Integer> 不是 List<Object> 的子类:
public static void printList(List<Object> list) { // ❌ 只能接受 List<Object>for (Object elem : list)System.out.println(elem);
}public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3);printList(numbers); // ❌ 编译错误
}
🔍 为什么?
List<Integer>不是List<Object>的子类(因为泛型是不协变的)。- Java 泛型中的
List<T>是不可变更类型的,即List<Integer>和List<Object>没有继承关系。
✅ 正确示例
import java.util.Arrays;
import java.util.List;public class UnboundedWildcard {public static void printList(List<?> list) { // ✅ 适用于任何 List 类型for (Object elem : list) { // ✅ 安全读取元素System.out.print(elem + " ");}System.out.println();}public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3);List<String> words = Arrays.asList("Hello", "World");List<Double> decimals = Arrays.asList(1.1, 2.2, 3.3);printList(numbers); // 输出: 1 2 3 printList(words); // 输出: Hello World printList(decimals); // 输出: 1.1 2.2 3.3}
}
🔍 解析
printList(List<?>)可以接受任何List<T>,如List<Integer>、List<String>、List<Double>等。Object elem安全读取list的元素,因为所有 Java 对象最终都继承自Object。- 但我们不能向
list添加元素(除了null)。
4. 为什么 List<Object> 和 List<?> 不一样?
在 Java 泛型中,List<Object> 和 List<?> 并不相同:
List<Object>只能存储Object及其子类,但不能存储Integer、String,因为List<Integer>不是List<Object>的子类。List<?>可以存储任何类型的List,但由于类型未知,无法向List<?>添加元素(除了null)。
❌ 错误示例
List<?> unknownList = new ArrayList<Integer>();
unknownList.add(5); // ❌ 编译错误
unknownList.add("Hello"); // ❌ 编译错误
unknownList.add(null); // ✅ 允许
🔍 为什么?
unknownList可以引用List<Integer>、List<String>、List<Double>,但Java 无法确定具体的类型,所以不允许添加元素。- 但**
null可以插入**,因为null适用于任何类型。
5. 适用场景
✅ 适用于不关心具体类型的 List(如通用的 printList 方法)。
✅ 适用于使用 Object 方法的情况(如 toString()、size()、clear())。
✅ 适用于泛型方法,使代码更加灵活。
6. 结论
✅ ? 表示“未知类型”,可以匹配任意泛型类型。
✅ List<?> 可以存储 List<T> 的任何类型,但不能添加元素(除了 null)。
✅ List<?> 与 List<Object> 不同,前者适用于任何 List<T>,而后者仅适用于 List<Object>。
✅ 使用 ? 让代码更加通用,提高可复用性。
🎯 记住口诀:
- 无界通配符
?适用于“只读”数据(与Object兼容)。 List<?>不能添加元素,避免类型不安全问题。List<?>适用于“泛型无关”的方法,如size()、clear()和toString()。
🚀 学会 ?,让你的 Java 泛型代码更灵活!
