Java类型擦除擦除我的泛型类型?

Mor*_*Adi 12 java generics jvm bytecode type-erasure

我认为java擦除会在编译时擦除泛型类型,但是当我自己测试它时,我意识到在Bytecode中有一些关于泛型类型的信息.

这是我的测试:

我写了2节课:

import java.util.*;
public class Test {
    List integerList;
} 
Run Code Online (Sandbox Code Playgroud)

import java.util.*;
public class Test {
    List<Integer> integerList;
} 
Run Code Online (Sandbox Code Playgroud)

我编译了这两个类和泛型类中的某个地方,我看到了这一行

integerList{blah blah}Ljava/util/List;{blah blah}
Signature{blah blah}%Ljava/util/List<Ljava/lang/Integer;>;{blah blah}<init>
Run Code Online (Sandbox Code Playgroud)

在非泛型类中:

integerList{blah blah}Ljava/util/List;{blah blah}<init>
Run Code Online (Sandbox Code Playgroud)

所以显然我在字节码里面有通用信息所以这个擦除的东西是什么?

Tom*_*ine 6

什么是这个擦除的东西?

擦除是从通用类型到原始类型的映射.常见的短语"因为擦除"基本上没有意义.重要的是使用映射的规范.

有两个有趣的用途.

  • 它用于将方法签名从使用泛型映射到原始类型.它是用于重载的原始类型签名.这导致绝大多数问题"擦除".例如,您不能有两种方法add(List<String>)并且add(List<Integer>)使用相同的类型.重载可能不是一个好主意,并且不太愿意添加此功能.

  • 在运行时可用于对象实例的类型是使用已擦除创建的类型.因此,如果你强制转换为(String)将在运行时进行检查,但是如果List<String>只转换为该类型的擦除(List)将被检查.您可以拥有类型的变量List<String>List<Integer>指向完全相同的实例.实际上,您不应该在1.5及更高版本中使用强制转换(引用类型).

在可行的情况下,通用信息保存在类文件中并通过反射提供.所以你会在类定义,超类型,字段,方法,构造函数等上找到它.


NIN*_*OOP 5

某些通用类型信息存储在Signature属性中.请参阅JLS 4.84.6以及JVM规范4.3.4.在这里阅读:

关于Java中泛型的最常见的抱怨可能是它们没有具体化 - 没有办法在运行时知道a与a List<String>有什么不同List<Long>.我已经习惯了这一点,我很惊讶地遇到了Neil Gafter在Super Type Tokens上的工作.事实证明,虽然JVM不会跟踪泛型类实例的实际类型参数,但它会跟踪泛型类的子类的实际类型参数.换句话说,虽然ArrayList<String>()new ArrayList()在运行时实际上只是一个新的,但如果一个类扩展ArrayList<String>,那么JVM知道这StringList's类型参数的实际类型参数.

Neal Gafter的博客.

  • 这是误导.元数据仍然只用于反射.它没有具体化. (2认同)