2023-01-06
泛型 类型
一. 代码重现
前几天有个学生小K编写集合代码时,运行的结果中却出现了一个自己没见过的异常,他不知道怎么解决,于是就跑来找辉哥帮忙。下面就是小K的代码,大家可以来看看,如下所示:
上述代码,一旦运行就会出现下图中的异常现象。说实话,对辉哥来说,只要一遇到bug,真是瞬间感觉连吃大盘鸡都不香了,必须立马盘它才行。
上图中,我们看到了一个叫做ClassCastException类型转换的异常!为什么会出现这个bug呢?其实如果我们仔细检查一下代码,就会发现原来是集合中的值写错了!我们声明的集合泛型是Double类型的,结果添加数据元素的时候,给集合添加了一个整型的元素,这样就造成了上述异常。而且根据错误信息的提示,异常出现在代码的第40行位置,现在我们知道了异常的原因和位置,接下来解决就容易了。
二. bug分析
其实上述代码中之所以会出现问题,是因为集合对泛型的严格要求所导致的。一开始小K觉着int类型可以直接转换为double类型,所以就往集合中添加了整型数据。但实际上Java中的集合泛型,要求的必须是包装类,我们的代码中就是Interger和Double,所以是无法将基本类型直接转为包装类型的。但小K却不明白,为什么基本类型与包装类型两者的类型不一致,但在往集合中添加数据时却可以添加进去呢?为了给小K讲明白这个问题,辉哥就通过javap命令带小K查看了反编译后的List类型,我们来看看泛型的底层究竟是个什么情况,如下图所示:
通过反编译可以看出,集合在底层编译时,其实所谓的泛型都被擦除了。也就是说,当我们在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。所以List和List在运行时事实上是相同的类型。而这其中原始类型的集合是特别容易出问题的,因为原始类型会跳过泛型检查且很不安全,List、List 和 List 等存在着巨大的差异,泛型在使用中很容易造成类型擦除。那么到底什么是泛型擦除?我们继续往下看。
三. 泛型的擦除
我们知道,Java泛型这个特性并不是一开始就有的,而是从JDK 1.5才开始加入的。因此Sun公司为了兼容之前的旧版本,Java对泛型的实现采取了“伪泛型”的策略,也就是说Java在语法上支持泛型,但在编译阶段会进行所谓的“类型擦除”(Type Erasure),将所有的泛型表示(尖括号中的内容)都替换为具体的类型(其对应的原生态类型),就像完全没有泛型一样。
并且泛型在擦除的时候,还会根据泛型的具体类型来进行。
四. 泛型相关知识回顾
泛型其实就是引用类型的占位符,主要用于避免引用类型的相互转换,替换之前使用的Object类型,去除不同类型之间的强转。
1. 泛型的应用
泛型主要可以用在 泛型类、泛型接口、泛型方法 上,也就是说,泛型可以在类、接口、方法上使用。
2. 泛型通配符
在泛型中,有几个常用的通配符,我们需要掌握。
?:表示右边的泛型可以是任意类型,还可以指定一个泛型的上限和下限。
泛型上限:
- 语法格式: 类型名称 对象名称
- 语法意义: 只能接收该类型及其子类
泛型下限:
- 语法格式: 类型名称 对象名称
- 语法意义: 只能接收该类型及其父类型
具体用法,如下图所示:
现在你知道为什么会出现上述异常了吗?对泛型的理解是否有进一步加深了呢?如果还有不明白的地方,可以给客服留言,客服会及时给你回复的。
上一篇:YARN的Job提交流程
下一篇:校园疫情信息化系统
开班时间:2021-04-12(深圳)
开班盛况开班时间:2021-05-17(北京)
开班盛况开班时间:2021-03-22(杭州)
开班盛况开班时间:2021-04-26(北京)
开班盛况开班时间:2021-05-10(北京)
开班盛况开班时间:2021-02-22(北京)
开班盛况开班时间:2021-07-12(北京)
预约报名开班时间:2020-09-21(上海)
开班盛况开班时间:2021-07-12(北京)
预约报名开班时间:2019-07-22(北京)
开班盛况Copyright 2011-2023 北京千锋互联科技有限公司 .All Right 京ICP备12003911号-5 京公网安备 11010802035720号