Java语法糖之泛型与类型擦除

简介: Java语法糖之泛型与类型擦除

1 泛型与类型擦除

泛型,JDK 1.5新特性,本质是参数化类型(Parametersized Type) 的应用,即所操作的数据类型被指定为一个参数。这种参数类型可用在:

  • 接口
  • 方法


的创建中, 分别称为:


  • 泛型类
  • 泛型接口
  • 泛型方法


在Java还没有泛型的版本时。只能通过:

  1. Object 是所有类型的父类
  2. 类型强制转换


两个特性协作实现类型泛化。例如,在哈希表的存取中,JDK 1.5之前使用HashMap的get() 方法,返回值就是个Object。由于Java语言里面所有的类型都维承于java.lang.Object,所以Object转型成任何对象都有可能。但也因为有无限的可能性,就只有程序员和运行期的虚拟机才知道这个Objet到底是个什么类型的对象。

编译期间,编译器无法检查该Object的强制转型是否成功。若仅仅依赖程序员去保障正确性,许多ClassCastException的风险就会延迟到程序运行期。


Java语言中的泛型则不一样,它只在程序源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型(Raw Type) ,并在相应地方插入强制转换代码。

因此,对运行期的Java来说AraylistAralist是同一个类。所以泛型是Java语言的一颗语法糖Java称为类型擦除,基于这种方法实现的泛型称为伪泛型。


  • 泛型擦除前的例子

image.png

把这段Java代码编译成Class文件,然后再用字节码反编译后,將会发现泛型都不见了,又变回了Java泛型出现之前的写法,泛型类型都变回了原类型。如:

image.png

通过擦除实现泛型,丧失了一些泛型思想应有的优雅

  • 当泛型遇见重载1

image.png

不能被编译的,因为参数ListList编译之后都被擦除了。变成了一样的原生类型List,擦除动作导致这两种方法的特征签名变得一模一样。初步看来,无法重载的原因已经找到了,但真的就如此吗? 只能说,泛型擦除成相同的原生类型只是无法重载的部分原因

  • 当泛型遇见置载2


1.png

由于Java泛型的引入,各种场景(虚拟机解析、反射等)下的方法调用都可能对原有基础产生影响,如在泛型类中如何获取传入的参数化类型等。因此,JCP组织对虚拟机规范做出了相应的修改,引入了诸如Signature、LocalVariableTypeTable 等新的属性用于解决伴随泛型而来的参数类型的识别问题,Signature 是其中最重要的一项属性,它的作用就是存储一个方法在字节码层面的特征签名,这个属性中保存的参数类型并不是原生类型,而是包括了参数化类型的信息。修改后的虚拟机规范要求所有能识别49.0以上版本的Class文件的虚拟机都要能正确地识别Signature参数。


从Signature属性的出现我们还可以得出结论,所谓的擦除,仅仅是对方法的Code属性中的字节码进行擦除,实际上元数据还是保留了泛型信息,这也是我们能通过反射取得参数化类型的根本依据。


  • 自动装箱: 拆箱与遍历循环

1.png

  • 自动装箱: 拆箱与遍历循环编译后

1.png

遍历循环则把代码还原成了迭代器的实现,这也是为何遍历循环需要被遍历的类实现Iterable接口的原因。最后再看看变长参数,它在调用的时候变成了一个数组类型的参数,在变长参数出现之前,程序员就是使用数组来完成类似功能的。

1.png

目录
相关文章
|
8天前
|
存储 传感器 缓存
java变量与数据类型:整型、浮点型与字符类型
### Java数据类型全景表简介 本文详细介绍了Java的基本数据类型和引用数据类型,涵盖每种类型的存储空间、默认值、取值范围及使用场景。特别强调了`byte`、`int`、`long`、`float`、`double`等基本类型在不同应用场景中的选择与优化,如文件流处理、金融计算等。引用数据类型部分则解析了`String`、数组、类对象、接口和枚举的内存分配机制。
41 15
|
9天前
|
Java
课时11:Java数据类型划分(浮点类型)
课时11介绍了Java中的浮点数据类型。主要内容包括:1. 定义小数,默认使用Double类型;2. 定义Float变量,需在数值后加"F"或"f"进行强制转换;3. 观察不同类型计算结果,如Int型除法会丢失精度,需至少包含一个Double或Float类型以确保准确性。总结指出,在复杂计算中推荐使用Double类型以避免精度损失。
|
9天前
|
Java
课时10:Java数据类型划分(整型类型)
本文主要围绕Java中整型数据展开,详细讲解整型变量、常量的概念,整型数据运算规则,包括数据溢出问题及解决方法,数据类型转换(自动转换与强制转换)的原理和注意事项,同时介绍了整型数据默认值的相关知识,以及byte数据类型与int数据类型的关系和使用场景,帮助读者全面掌握Java整型数据的相关内容。
|
5月前
|
Java 开发工具 Android开发
Kotlin语法笔记(26) -Kotlin 与 Java 共存(1)
本系列教程笔记详细讲解了Kotlin语法,适合需要深入了解Kotlin的开发者。若需快速学习Kotlin,建议查看“简洁”系列教程。本期重点介绍了Kotlin与Java的共存方式,包括属性、单例对象、默认参数方法、包方法、扩展方法以及内部类和成员的互操作性。通过这些内容,帮助你在项目中更好地结合使用这两种语言。
75 1
|
3月前
|
Java
java do while 的语法怎么用?
java do while 的语法怎么用?
90 3
|
4月前
|
存储 Java 开发者
Java 中 Set 类型的使用方法
【10月更文挑战第30天】Java中的`Set`类型提供了丰富的操作方法来处理不重复的元素集合,开发者可以根据具体的需求选择合适的`Set`实现类,并灵活运用各种方法来实现对集合的操作和处理。
|
4月前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
120 2
|
4月前
|
存储 Java 编译器
Java泛型类型擦除以及类型擦除带来的问题
泛型擦除是指Java编译器在编译期间会移除所有泛型信息,使所有泛型类型在运行时都变为原始类型。例如,`List<String>` 和 `List<Integer>` 在JVM中都视为 `List`。因此,通过 `getClass()` 比较两个不同泛型类型的 `ArrayList` 实例会返回 `true`。此外,通过反射调用 `add` 方法可以向 `ArrayList<Integer>` 中添加字符串,进一步证明了泛型信息在运行时被擦除。
95 2
|
5月前
|
Java API
[Java]泛型
本文详细介绍了Java泛型的相关概念和使用方法,包括类型判断、继承泛型类或实现泛型接口、泛型通配符、泛型方法、泛型上下边界、静态方法中使用泛型等内容。作者通过多个示例和测试代码,深入浅出地解释了泛型的原理和应用场景,帮助读者更好地理解和掌握Java泛型的使用技巧。文章还探讨了一些常见的疑惑和误区,如泛型擦除和基本数据类型数组的使用限制。最后,作者强调了泛型在实际开发中的重要性和应用价值。
130 0
[Java]泛型
|
5月前
|
Java 编译器 Android开发
Kotlin语法笔记(28) -Kotlin 与 Java 混编
Kotlin语法笔记(28) -Kotlin 与 Java 混编
80 2

热门文章

最新文章