【Java基础-46.3】Java泛型通配符详解:解锁类型安全的灵活编程

ops/2025/2/21 17:23:26/

在Java中,泛型(Generics)是提高代码复用性和类型安全的重要特性。然而,泛型的严格类型约束有时会限制代码的灵活性。为了解决这个问题,Java引入了泛型通配符(Wildcards),它允许我们编写更通用的代码,同时保持类型安全。本文将深入探讨泛型通配符的概念、用法以及实际应用场景。


1. 泛型通配符是什么?

泛型通配符用?表示,它代表一种未知的类型。通配符通常用于以下场景:

  • 处理泛型集合时,允许接受多种类型的参数。
  • 在方法参数或返回值中,提供更灵活的类型支持。

通配符可以分为以下三种:

  1. 无界通配符(Unbounded Wildcard)<?>
  2. 上界通配符(Upper Bounded Wildcard)<? extends T>
  3. 下界通配符(Lower Bounded Wildcard)<? super T>

2. 无界通配符(<?>)

无界通配符表示任意类型。它通常用于以下场景:

  • 当你只关心泛型集合的操作(如遍历),而不关心具体类型时。

2.1 示例:遍历任意类型的集合

java">public static void printList(List<?> list) {for (Object item : list) {System.out.println(item);}
}public static void main(String[] args) {List<Integer> intList = Arrays.asList(1, 2, 3);List<String> strList = Arrays.asList("A", "B", "C");printList(intList); // 输出:1 2 3printList(strList); // 输出:A B C
}

在这个例子中,printList方法可以接受任何类型的List,因为<?>表示未知类型。


3. 上界通配符(<? extends T>)

上界通配符表示“某种类型或其子类型”。它通常用于以下场景:

  • 当你需要从泛型集合中读取数据,但不允许写入数据时。

3.1 示例:处理数字类型的集合

java">public static double sumOfList(List<? extends Number> list) {double sum = 0.0;for (Number num : list) {sum += num.doubleValue();}return sum;
}public static void main(String[] args) {List<Integer> intList = Arrays.asList(1, 2, 3);List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);System.out.println(sumOfList(intList));    // 输出:6.0System.out.println(sumOfList(doubleList)); // 输出:6.6
}

在这个例子中,sumOfList方法可以接受Number或其子类型(如IntegerDouble)的集合。

注意事项:

  • 使用<? extends T>时,只能从集合中读取数据,不能写入数据(除了null),因为具体类型未知。

4. 下界通配符(<? super T>)

下界通配符表示“某种类型或其父类型”。它通常用于以下场景:

  • 当你需要向泛型集合中写入数据,但不关心读取数据的类型时。

4.1 示例:向集合中添加元素

java">public static void addNumbers(List<? super Integer> list) {for (int i = 1; i <= 5; i++) {list.add(i);}
}public static void main(String[] args) {List<Number> numList = new ArrayList<>();List<Object> objList = new ArrayList<>();addNumbers(numList); // 添加Integer到Number集合addNumbers(objList); // 添加Integer到Object集合System.out.println(numList); // 输出:[1, 2, 3, 4, 5]System.out.println(objList); // 输出:[1, 2, 3, 4, 5]
}

在这个例子中,addNumbers方法可以向Integer或其父类型(如NumberObject)的集合中添加元素。

注意事项:

  • 使用<? super T>时,可以向集合中写入数据,但读取数据时只能以Object类型接收。

5. PECS原则

为了更清晰地理解上界和下界通配符的使用场景,我们可以参考PECS原则

  • Producer Extends:如果泛型集合是生产者(提供数据),使用<? extends T>
  • Consumer Super:如果泛型集合是消费者(接收数据),使用<? super T>

5.1 示例:结合PECS原则

java">public static <T> void copy(List<? extends T> src, List<? super T> dest) {for (T item : src) {dest.add(item);}
}public static void main(String[] args) {List<Integer> src = Arrays.asList(1, 2, 3);List<Number> dest = new ArrayList<>();copy(src, dest); // 将Integer集合复制到Number集合System.out.println(dest); // 输出:[1, 2, 3]
}

在这个例子中,src是生产者(提供数据),因此使用<? extends T>dest是消费者(接收数据),因此使用<? super T>


6. 实际应用场景

6.1 集合工具类

Java标准库中的Collections工具类大量使用了泛型通配符。例如:

java">public static <T> void sort(List<T> list, Comparator<? super T> c) {// 排序逻辑
}

这里使用<? super T>是为了允许传入T或其父类型的比较器。

6.2 泛型方法

在编写泛型方法时,通配符可以提高方法的灵活性。例如:

java">public static <T> void printFirst(List<? extends T> list) {if (!list.isEmpty()) {System.out.println(list.get(0));}
}

7. 总结

泛型通配符是Java泛型中一个强大的工具,它通过<?><? extends T><? super T>提供了灵活的类型支持。理解并掌握通配符的用法,可以帮助你编写更通用、更安全的代码。记住PECS原则,合理选择上界和下界通配符,可以让你的代码更加优雅和高效。


http://www.ppmy.cn/ops/160295.html

相关文章

【QT】第一个 QT程序(对象树)

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Qt 目录 一&#xff1a;&#x1f525; QtHelloWorld程序 &#x1f98b; 使⽤"标签"实现纯代码⽅式实现可视化操作实现 &#x1f98b; 使⽤"按钮"实现可视化操作实现纯代码实现…

【Python项目】文本相似度计算系统

【Python项目】文本相似度计算系统 技术简介&#xff1a;采用Python技术、Django技术、MYSQL数据库等实现。 系统简介&#xff1a;本系统基于Django进行开发&#xff0c;包含前端和后端两个部分。前端基于Bootstrap框架进行开发&#xff0c;主要包括系统首页&#xff0c;文本分…

Windows Docker Desktop部署MaxKB详细教程

MaxKB(Max Knowledge Base)是一款基于大语言模型(LLM)和检索增强生成(RAG)技术的开源知识库问答系统,旨在帮助企业、教育机构及研究组织高效管理知识并提供智能问答服务。 一、前期准备工作 首先,你需要再你的Windows电脑上安装 Docker Desktop。本章教程,不介绍如何安…

设计模式3:代理、适配器、装饰器模式

代理模式&#xff08;Proxy Pattern&#xff09; 代理模式的本质是⼀个中间件&#xff0c;主要⽬的是解耦合服务提供者和使⽤者。使⽤者通过代理间接访问服务提供者&#xff0c;便于后者的封装和控制。是⼀种结构型设计模式。 静态代理和动态代理区别 静态代理&#xff1a;编…

【核心算法篇十六】《DeepSeek强化学习:MuZero算法核心解析》

引言:当强化学习不再需要环境说明书 2016年AlphaGo击败李世石让世界认识了蒙特卡洛树搜索(MCTS)的威力,2017年AlphaZero用通用算法征服围棋、象棋、将棋三大棋类。但它们的共同局限在于:必须预先知道环境的完整规则(比如棋盘如何落子、得分如何计算)。而2019年DeepMind…

WPF7-数据绑定基础

1. WPF数据绑定试验 1.1. 数据绑定的核心实现1.2. {Binding}语法1.3. 理解 DataContext 1. WPF数据绑定试验 以下是一个简单的 WPF 数据绑定示例&#xff0c;使用两个TextBox控件分别表示Name和Age来进行进行数据绑定试验。 数据模型类 创建一个 Person 类&#xff0c;包含…

Android嵌套滑动造成的滑动冲突原理分析

嵌套滑动造成的滑动冲突原理分析 场景复现&#xff1a; CoordinatorLayout AppBarLayout Vertical RecyclerView Horizontal RecycleView Horizontal RecycleView 是Vertical RecyclerView的一个子view, CoordinatorLayout 实现了AppBarLayout 和 RecyclerView的协调联动…

光子神经网络:为人工智能注入 “光” 速动力

光子神经网络&#xff08;Photonic Neural Networks, PNNs&#xff09;是利用光子学技术实现的人工神经网络&#xff0c;旨在通过光的高速传输和并行处理能力&#xff0c;突破传统电子计算在速度和能效上的限制。以下是光子神经网络的关键内容&#xff1a; 1. 光子神经网络的优…