Java 中的类型擦除

2024 年 9 月 10 日 | 阅读 3 分钟

Java 语言中引入泛型的概念,是为了在编译时进行更严格的类型检查,并支持泛型编程。为了实现泛型,Java 编译器应用类型擦除(Type Erasure)来

  1. 将泛型中的所有参数类型替换为界限或 Object(当参数类型没有界限时)。因此,生成的字节码只包含普通的类、接口和方法。
  2. 在需要时插入类型转换,以支持类型安全。
  3. 生成桥接方法,以保持泛型类型的多态性,当泛型类型被继承时。

通常,编译后的泛型代码在谈论 P(或任何其他类型参数)时,实际上只使用了 java.lang.Object - 并且存在一些信息(元数据),告诉 Java 编译器它是一个泛型类型。当一个人针对方法或泛型类型编译代码时,Java 编译器会解析这个人真正想要的意思(即,编译器找出 P 的类型参数),并在编译时验证你是否在做正确的事情。然而,生成的代码仍然是根据 java.lang.Object 来处理的 - Java 编译器会在需要的地方生成额外的类型转换。在运行时,List 和 List 是相同的。Java 编译器会擦除额外的类型信息。

编译后,类型参数 P 被默认的 Object 替换。请看以下程序。

让我们来看另一个例子,其中类型参数 P 扩展了 java.lang.String 类。

编译后,我们得到

类型擦除的实现

让我们看一个类型擦除实现的例子。

文件名: TypeErasure2.java

输出

Hello
World

解释: 在这里,当代码编译时,编译器不会发出任何警告。这是由于类型擦除。

现在,请看下面的程序。

文件名: TypeErasure3.java

当我们使用 javac 命令编译上述程序时,我们会收到以下警告。这是因为类型擦除,因为程序中没有指明所使用的 List 的类型。

注意:TypeErasure3.java 使用了未检查或不安全的操作。使用 -Xlint:unchecked 重新编译以获取详细信息。

输出仍然相同。

输出

Hello
World