当前位置: 首页 > news >正文

Java泛型通配符详解:搞懂?/extends/super用法,避开集合操作踩坑点

上次跟你们聊了泛型的基础用法,今天接着往下说 —— 泛型里还有个挺重要的概念叫 “通配符”,就是那个问号 “?”,很多人第一次见都懵:这玩意儿跟普通泛型有啥区别?为啥有时候非得用它不可?小索奇当初也卡这儿好久,后来拿实际例子一琢磨,才彻底明白它的用处。

先给你出个题:假如你写了个方法,要打印所有 List 集合里的元素,不管这个 List 装的是 String、Integer 还是别的类型,该咋写?

你可能会想,直接用 List不就行了?比如这样:

public static void printList(List list) {

for (T item : list) {

System.out.println(item);

}

}

这么写没问题,但还有个更简洁的方式 —— 用通配符 “?”:

public static void printList (List<?> list) {

for (Object item : list) {

System.out.println (item);

}

}

看出区别没?用通配符的话,不用定义泛型参数,代码更短。而且这两种写法效果一样,不管你传 List还是 List,都能正常打印。那为啥要有两种写法呢?其实核心区别在于:如果方法里不需要用到泛型的具体类型,只用通配符就够了;要是需要操作具体类型(比如给集合加元素),就得用

比如你想写个方法,给 List 里加一个默认元素,这时候用通配符就不行了:

// 这段代码会编译报错!

public static void addDefault (List<?> list) {

list.add ("默认值"); // 报错:无法确定?的类型,不能加 String

}

这背后的原因是啥呢?因为通配符 “?” 代表 “未知类型”,编译器不知道这个 List 到底装的是啥,自然不敢让你随便加元素 —— 万一人家是 List,你硬塞个 String 进去,不就乱套了?

但用就能搞定:

public static void addDefault(List list, T defaultValue) {

list.add(defaultValue);

}

调用的时候指定类型就行,比如给 List加默认值:

List strList = new ArrayList<>();

addDefault (strList, "默认值"); // 没问题

是不是一下子就懂了?简单说就是:通配符适合 “只读” 场景(比如打印集合),泛型参数适合 “读写” 场景(比如给集合加元素)。

除了单纯的 “?”,通配符还有两种常用写法:<? extends T > 和 <? super T>,这俩也特容易搞混,小索奇当初记了好几天才分清。

先看 <? extends T>,它代表 “T 及其子类”。比如 <? extends Number>,就包括 Integer、Double、Long 这些 Number 的子类。这种写法的特点是 “能读不能写”(跟普通?类似,但多了类型限制)。比如你写个方法,求所有 Number 类型集合的总和:

public static double sum (List<? extends Number> list) {

double total = 0;

for (Number num : list) {

total += num.doubleValue ();

}

return total;

}

不管你传 List还是 List,都能算总和,因为它们都是 Number 的子类。但还是不能往里面加元素,比如 list.add (10) 会报错 —— 因为编译器不知道具体是 Integer 还是 Double,怕加错类型。

再看 <? super T>,它代表 “T 及其父类”。比如 <? super Integer>,就包括 Number、Object 这些 Integer 的父类。这种写法的特点是 “能写不能读”(或者说读出来是 Object 类型)。比如你想写个方法,给 List 里加多个 Integer 元素:

public static void addIntegers (List<? super Integer> list) {

list.add (1);

list.add (2); // 没问题,因为?至少是 Integer 类型

}

调用的时候,传 List、List甚至 List都能行。但读元素的时候,只能用 Object 接收:

for (Object obj : list) {

// 要想用 Integer,得手动强转

Integer num = (Integer) obj;

}

小索奇之前做统计功能时,就用 <? super Integer> 存过数据 —— 既可以存到 Integer 列表,也能存到 Number 列表,灵活度特别高。

最后给你总结个小口诀,记起来更方便:“上界 extends 能读不能写,下界 super 能写不能读,通配符?只读不写,泛型读写都能搞”。

你们平时写代码时,有没有用过通配符却踩了坑的?比如想加元素加不进去,或者不知道该用 extends 还是 super?可以在评论区跟小索奇聊聊,咱们一起把泛型这点事儿彻底搞明白~

搜索即兴小索奇,点击关注,加入社区群聊,获取更多好用工具和资源

http://www.dtcms.com/a/361228.html

相关文章:

  • 快递地址归类排序实现(Java Python)
  • Jenkins 自动构建Vue 项目的一个大坑
  • JVM核心机制:类加载与内存结构详解
  • OpenHarmony智能语音框架深度拆解:从VAD到唤醒词打造你的AI语音智能体
  • 自动化软件测试工具Parasoft C/C++test如何实现运行时错误的检测与修复
  • 面试经典150题[021]:反转字符串中的单词(LeetCode 151)
  • 【XR技术概念科普】VST(视频透视)vs OST(光学透视):解码MR头显的两种核心技术路径
  • 「数据获取」《中国住户调查年鉴》(2000-2024)(获取方式看绑定的资源)
  • SQLark:一款面向信创应用开发者的数据库开发和管理工具
  • Jmeter实现参数化的4种方式
  • Windows神器,按键屏蔽
  • 【机器学习学习笔记】pandas基础
  • (纯新手教学)计算机视觉(opencv)实战十二——模板匹配(cv2.matchTemplate)
  • UE角色取消被Decal影响
  • Jetson AGX Orin平台R36.3.0版本1080P25fps MIPI相机图像采集异常调试记录
  • 基于单片机电动车充电桩/充电车棚环境监测设计
  • 基于RS-485接口的芯片的FPGA驱动程序
  • 吴恩达机器学习作业十二:协同过滤(电影推荐系统)
  • 广电手机卡到底好不好?
  • Git基础使用和PR贡献
  • .Net程序员就业现状以及学习路线图(二)
  • Android面试指南(六)
  • 大模型落地全流程实践:从技术选型到企业级部署
  • 音视频开发入门:FFmpeg vs GStreamer,新手该如何选择?
  • 松灵斯坦福Mobile ALOHA同款 | 通过低成本全身远程操作实现双手机器人移动操控学习
  • 01数据结构-红黑树
  • 永磁同步电机无速度算法--高频脉振方波注入法(测量轴系转子位置误差信号解耦处理)
  • Spark引擎中RDD的性质
  • 【牛客JZ31】—栈的压入弹出序列判断算法详解
  • 【73页PPT】MES应用介绍(附下载方式)