【Java】泛型在 Java 中是怎样实现的?

先说结论 , Java 的泛型是伪泛型 , 在运行期间不存在泛型的概念 , 泛型在 Java 中是 编译检查 + 运行强转 实现的

泛型是指 允许在定义类 , 接口和方法时使用的类型参数 , 使得代码可以在不指定具体类型的情况下操作不同的数据类型 , 从而实现类型安全的代码复用 的语言机制 .

集合框架和内置函数式接口等内容都使用了泛型 .

通配符

<>泛型类型参数列表 , 可以包含多个参数 .

?通配符 , 可以配合 extends 和 super 关键字表示不明类型的上下限 .

<T> 通常用于泛型类源码声明 , T 作为占位符表示实例化的泛型参数 .

<?> 可以用在实例化上 , 此时泛型参数不明确 , 通常不能写入变量 .

不能 Box<?> box = new Box<?>(); , 但可以声明 Box<?> box = new Box<String>(); , 这样只能安全读取 Object 元素 , 不能写入任何非 null 元素 . new 语句右侧的 <> 叫做钻石操作符 , 钻石操作符的作用是让编译器根据左侧泛型参数推断右侧的实际参数 . 如果左侧是 <?> 参数不明 , 那么右侧则必须显式指定泛型参数 .

通配符写法作用允许读取允许写入
<?>任意类型可以读取为 Object只能写入 null
<? extends T>T 或其子类型(上界)可以读取为 T不能写入具体元素
<? super T>T 或其父类型(下界)只能读取为 Object可以写入 T 或子类型

生产消费原则 ( PECS )

Producer Extends, Consumer Super .

  • 生产者使用 <? extends T> 上界通配符 : 只能读 , 不能写 .
List<? extends Number> list = new ArrayList<Integer>();

list 是 Number 或其子类类型的集合 , 可以安全地将集合元素当作 Number 读取 , 因为确定是 Number 及其子类 .

只能确定泛型参数的上界 , 实际类型不确定 , 所以不允许写入 .

  • 消费者使用 <? super T> 下界通配符 : 只能写 , 读不明白 .
List<? super Integer> list = new ArrayList<Number>();

list 是 Integer 或其父类类型的集合 , 因为 Java 向下转型是安全的 , 所以可以将 Integer 或其子类放入集合 , 因为集合元素类型一定是 Integer 或其父类 .

因为只能确定泛型参数的下界 , 所以编译期将 ? super Integer 擦除成 Object , 且读取时只能保证元素是 Object .

类型擦除

编译器将泛型类型替换成原始类型以保证向后兼容性 ( 兼容不支持泛型的旧版本 Java ) , 向类 , 接口或方法传递的泛型类型参数 类名<类型> 只在编译期存在 , 编译后泛型信息会被擦除 , 生成的字节码文件不包含具体的泛型类型 .

类型参数被擦除为它的第一个边界类型 : 如果是 T , 则擦除为祖宗类 Object , 如果是 T extends 父类 , 则擦除为父类 . 集合中 List<T> 擦除为 List .

List<String> list = new ArrayList<>();
List.add("Hello");
String s = List.get(0);👇
(在字节码中类似于)
List list = new ArrayList();
list.add("Hello");
String s = (String)list.get(0);

instanceof 关键字用于判断对象是否是某个类或其子类的实例 , a instanceof b 作为语句返回布氏值 .

Tips : 基本数据类型不具备继承体系 , 也不是对象 , 不能被泛型的擦除机制处理 , 所以泛型必须使用基本数据类型的包装类 .

类型擦除会导致

  1. 运行时不知道泛型类型 .

    List<String> a = new ArrayList<>();
    List<Integer> b = new ArrayList<>();
    a.equals(b); // true
    a.getClass() == b.getClass() // true
    
  2. 泛型不能用于静态字段 . 因为不同泛型实例在运行时本质上是同一个类 , 它们会共享同一个静态字段 , 如果这个静态字段是泛型参数 T 的 , 那么就会出现实例类型冲突 ( 静态字段只有一份 , 不同实例期望的类型却不同 ) .

  3. 不能用 instanceof 关键字判别泛型类 . 因为不同的泛型类在运行时被擦除为同一个类 , 此时再使用 instanceof 关键字没有任何意义 .

编译期类型检查

仍然以集合为例 , 编译期完成的任务有 :

  1. 检测传入泛型集合的字段类型是否正确 .

    List<String> list = new ArrayList<>();
    list.add("Hello");
    list.add(123); // 编译错误, int 不是 String
    
  2. 取出泛型集合对象时是否能正确映射 .

    int get = list.get(0); // 编译错误, 不能把 String 当作 int
    

类型检查本质是继承链的转换关系 , 前面提到的向上转型机制在通配符 , 类型擦除和类型检查等特性上得到充分实现 .

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/83999.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux如何查找软连接的实际地址

在Linux系统中&#xff0c;查找软连接&#xff08;符号链接&#xff0c;即symbolic link&#xff09;的实际地址可以通过多种方法实现。软连接是一个特殊的文件类型&#xff0c;它包含了一个指向另一个文件或目录的引用。要找到软连接所指向的实际文件或目录&#xff0c;可以使…

Token类型与用途详解:数字身份的安全载体图谱

在现代数字身份体系中&#xff0c;Token如同"数字DNA"&#xff0c;以不同形态流转于各类应用场景。根据Okta的最新研究报告&#xff0c;平均每个企业应用使用2.7种不同类型的Token实现身份验证和授权。本文将系统梳理主流Token类型及其应用场景&#xff0c;通过行业典…

火山 RTC 引擎9 ----集成 appkey

一、集成 appkey 1、网易RTC 初始化过程 1&#xff09;、添加头文件 实现互动直播 - 互动直播 2.0网易云信互动直播产品的基本功能包括音视频通话和连麦直播&#xff0c;当您成功初始化 SDK 之后&#xff0c;您可以简单体验本产品的基本业务流程&#xff0c;例如主播加入房间…

详细介绍Qwen3技术报告中提到的模型架构技术

详细介绍Qwen3技术报告中提到的一些主流模型架构技术&#xff0c;并为核心流程配上相关的LaTeX公式。 这些技术都是当前大型语言模型&#xff08;LLM&#xff09;领域为了提升模型性能、训练效率、推理速度或稳定性而采用的关键组件。 1. Grouped Query Attention (GQA) - 分组…

光电效应理论与实验 | 从爱因斯坦光量子假说到普朗克常量测定

注&#xff1a;本文为“光电效应”相关文章合辑。 英文引文&#xff0c;机翻未校。 中文引文&#xff0c;略作重排&#xff0c;未整理去重。 图片清晰度受引文原图所限。 如有内容异常&#xff0c;请看原文。 Photoelectric Effect 光电效应 Discussion dilemma Under the…

Visual Studio 2019/2022:当前不会命中断点,还没有为该文档加载任何符号。

1、打开调试的模块窗口&#xff0c;该窗口一定要在调试状态下才会显示。 vs2019打开调试的模块窗口 2、Visual Studio 2019提示未使用调试信息生成二进制文件 未使用调试信息生成二进制文件 3、然后到debug目录下看下确实未生成CoreCms.Net.Web.WebApi.pdb文件。 那下面的…

打破性能瓶颈:用DBB重参数化模块优化YOLOv8检测头

文章目录 引言DBB 重参数化模块简介DBB 的优势 YOLOv8 检测头的结构分析使用 DBB 模块魔改检测头替换策略代码实现改进后的效果预期 实验与验证总结与展望 引言 在目标检测领域&#xff0c;YOLO 系列算法一直以其高效的检测速度和不错的检测精度受到广泛关注。随着版本的不断更…

如何成为更好的自己?

成为更好的自己是一个持续成长的过程&#xff0c;需要结合自我认知、目标规划和行动力。以下是一些具体建议&#xff0c;帮助你逐步提升&#xff1a; 1. 自我觉察&#xff1a;认识自己 反思与复盘&#xff1a;每天花10分钟记录当天的决策、情绪和行为&#xff0c;分析哪些做得…

免费使用GPU的探索笔记

多种有免费时长的平台 https://www.cnblogs.com/java-note/p/18760386 Kaggle免费使用GPU的探索 https://www.kaggle.com/ 注册Kaggle账号 访问Kaggle官网&#xff0c;使用邮箱注册账号。 发现gpu都是灰色的 返回home&#xff0c;右上角的头像点开 验证手机号 再次code-you…

CSS- 4.2 相对定位(position: relative)

本系列可作为前端学习系列的笔记&#xff0c;代码的运行环境是在HBuilder中&#xff0c;小编会将代码复制下来&#xff0c;大家复制下来就可以练习了&#xff0c;方便大家学习。 HTML系列文章 已经收录在前端专栏&#xff0c;有需要的宝宝们可以点击前端专栏查看&#xff01; 点…

如何使用Antv X6使用拖拽布局?

拖拽效果图 拖拽后 布局预览 官方&#xff1a; X6 图编辑引擎 | AntV 安装依赖 # npm npm install antv/x6 --save npm install antv/x6-plugin-dnd --save npm install antv/x6-plugin-export --save需要引入的代码 import { Graph, Shape } from antv/x6; import { Dnd } …

数据库健康监测器(BHM)实战:如何通过 HTML 报告识别潜在问题

在数据库运维中,健康监测是保障系统稳定性与性能的关键环节。通过 HTML 报告,开发者可以直观查看数据库的运行状态、资源使用情况与潜在风险。 本文将围绕 数据库健康监测器(Database Health Monitor, BHM) 的核心功能展开分析,结合 Prometheus + Grafana + MySQL Export…

PCB设计实践(二十四)PCB设计时如何避免EMI

PCB设计中避免电磁干扰&#xff08;EMI&#xff09;是一项涉及电路架构、布局布线、材料选择及制造工艺的系统工程。本文从设计原理到工程实践&#xff0c;系统阐述EMI产生机制及综合抑制策略&#xff0c;覆盖高频信号控制、接地优化、屏蔽技术等核心维度&#xff0c;为高密度、…

嵌入式硬件篇---陀螺仪|PID

文章目录 前言1. 硬件准备主控芯片陀螺仪模块电机驱动电源其他2. 硬件连接3. 软件实现步骤(1) MPU6050初始化与数据读取(2) 姿态解算(互补滤波或DMP)(3) PID控制器设计(4) 麦克纳姆轮协同控制4. 主程序逻辑5. 关键优化与调试技巧(1) 传感器校准(2) PID参数整定先调P再调D最后…

【Linux基础I/O】文件调用接口、文件描述符、重定向和缓冲区

【Linux基础I/O一】文件描述符和重定向 1.C语言的文件调用接口2.操作系统的文件调用接口2.1open接口2.2close接口2.3write接口2.4read接口 3.文件描述符fd的本质4.标准输入、输出、错误5.重定向5.1什么是重定向5.2输入重定向和输出重定向5.3系统调用的重定向dup2 6.缓冲区 1.C语…

鸿蒙HarmonyOS 【ArkTS组件】通用属性-背景设置

&#x1f4d1;往期推文全新看点&#xff08;附带最新鸿蒙全栈学习笔记&#xff09; 嵌入式开发适不适合做鸿蒙南向开发&#xff1f;看完这篇你就了解了~ 鸿蒙岗位需求突增&#xff01;移动端、PC端、IoT到底该怎么选&#xff1f; 分享一场鸿蒙开发面试经验记录&#xff08;三面…

【76. 最小覆盖子串】

Leetcode算法练习 笔记记录 76. 最小覆盖子串 76. 最小覆盖子串 滑动窗口的hard题目&#xff0c;思路先找到第一个覆盖的窗口&#xff0c;不断缩小左边界&#xff0c;找到更小的窗口并记录。 思路很简单&#xff0c;写起来就不是一会事了&#xff0c;看题解看了几个h&#xff0…

Spring事务简单操作

什么是事务&#xff1f; 事务是一组操作的集合&#xff0c;是一个不可分割的操作 事务会把所有的操作作为⼀个整体, ⼀起向数据库提交或者是撤销操作请求. 所以这组操作要么同时 成功, 要么同时失败. 事务的操作 分为三步&#xff1a; 1. 开启事start transaction/ begin …

Rust 学习笔记:关于错误处理的练习题

Rust 学习笔记&#xff1a;关于错误处理的练习题 Rust 学习笔记&#xff1a;关于错误处理的练习题想看到回溯&#xff0c;需要把哪个环境变量设置为 1&#xff1f;以下哪一项不是使用 panic 的好理由&#xff1f;以下哪一项最能描述为什么 File::open 返回的是 Result 而不是 O…

MCP 协议传输机制大变身:抛弃 SSE,投入 Streamable HTTP 的怀抱

在技术的江湖里&#xff0c;变革的浪潮总是一波接着一波。最近&#xff0c;模型上下文协议&#xff08;MCP&#xff09;的传输机制就搞出了大动静&#xff0c;决定和传统的服务器发送事件&#xff08;SSE&#xff09;说拜拜&#xff0c;转身拥抱 Streamable HTTP&#xff0c;这…