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)
所以显然我在字节码里面有通用信息所以这个擦除的东西是什么?
什么是这个擦除的东西?
擦除是从通用类型到原始类型的映射.常见的短语"因为擦除"基本上没有意义.重要的是使用映射的规范.
有两个有趣的用途.
它用于将方法签名从使用泛型映射到原始类型.它是用于重载的原始类型签名.这导致绝大多数问题"擦除".例如,您不能有两种方法add(List<String>)并且add(List<Integer>)使用相同的类型.重载可能不是一个好主意,并且不太愿意添加此功能.
在运行时可用于对象实例的类型是使用已擦除创建的类型.因此,如果你强制转换为(String)将在运行时进行检查,但是如果List<String>只转换为该类型的擦除(List)将被检查.您可以拥有类型的变量List<String>并List<Integer>指向完全相同的实例.实际上,您不应该在1.5及更高版本中使用强制转换(引用类型).
在可行的情况下,通用信息保存在类文件中并通过反射提供.所以你会在类定义,超类型,字段,方法,构造函数等上找到它.
某些通用类型信息存储在Signature属性中.请参阅JLS 4.8 和4.6以及JVM规范4.3.4.在这里阅读:
关于Java中泛型的最常见的抱怨可能是它们没有具体化 - 没有办法在运行时知道a与a
List<String>有什么不同List<Long>.我已经习惯了这一点,我很惊讶地遇到了Neil Gafter在Super Type Tokens上的工作.事实证明,虽然JVM不会跟踪泛型类实例的实际类型参数,但它会跟踪泛型类的子类的实际类型参数.换句话说,虽然ArrayList<String>()newArrayList()在运行时实际上只是一个新的,但如果一个类扩展ArrayList<String>,那么JVM知道这String是List's类型参数的实际类型参数.
| 归档时间: |
|
| 查看次数: |
1219 次 |
| 最近记录: |