问题
Java中泛型的擦除概念是什么?
#1 热门回答(177 赞)
它基本上是通过编译器技巧在Java中实现泛型的方式。编译的通用代码实际上只使用java.lang.Object
,无论你谈论T
(或其他一些类型参数) - 并且有一些元数据告诉编译器它确实是泛型类型。
当你针对泛型类型或方法编译一些代码时,编译器会计算出你的真正含义(即T
的类型参数),并验证atcompiletime你正在做正确的事情,但是发出的代码再次只是根据java.lang.Object
进行说明 - 编译器在必要时生成额外的强制转换。在执行时,aList<String>
和aList<Date>
完全相同;额外的类型信息由编译器提供。
将此与C#进行比较,其中信息在执行时保留,允许代码包含表达式,例如typeof(T)
,相当于T.class
-除了后者无效。 (请注意,.NET泛型和Java泛型之间存在进一步的差异。)类型擦除是处理Java泛型时许多"奇怪"警告/错误消息的来源。
其他资源:
- Oracle文档
- 维基百科
- Gilad Bracha的Java泛型指南(PDF - 强烈推荐;链接可能需要定期更改)
- Angelika Langer的Java Generics FAQ
#2 热门回答(36 赞)
就像旁注一样,实际看到编译器在执行擦除时正在做什么是一个有趣的练习 - 使整个概念更容易掌握。有一个特殊的标志,你可以传递编译器输出已经删除了泛型和插入的强制转换的java文件。一个例子:
javac -XD-printflat -d output_dir SomeFile.java
The-printflat
是传递给生成文件的编译器的标志。 (The-XD
part是告诉javac
把它交给实际编译的可执行jar而不是justjavac
,但我离题了......)The-d output_dir
是必要的,因为编译器需要一些地方来放置新的.java文件。
当然,这不仅仅是擦除;编译器完成的所有自动操作都在这里完成。例如,还插入了默认构造函数,新的foreach-stylefor
loops扩展为regularfor
loops等。很高兴看到自动发生的小事情。
#3 热门回答(25 赞)
要完成已经非常完整的Jon Skeet的答案,你必须实现type erasure的概念,因为需要与先前版本的Java兼容。
最初在EclipseCon 2007上展示(不再可用),兼容性包括以下几点:
- 源兼容性(很高兴......)
- 二进制兼容性(必须!)
- 迁移兼容性现有程序必须继续工作现有的库必须能够使用泛型类型必须具备!
原始答案:
因此:
new ArrayList<String>() => new ArrayList()
有更多的命题为reification。实现"将抽象概念视为真实",其中语言结构应该是概念,而不仅仅是语法糖。
我还应该提到Java 6的checkCollection
方法,它返回指定集合的动态类型安全视图。任何插入错误类型元素的尝试都将导致immediateClassCastException
。
language中的泛型机制提供了编译时(静态)类型检查,但是可以通过未经检查的强制转换来破坏这种机制。
通常这不是问题,因为编译器会对所有此类未经检查的操作发出警告。
但是,有时单独进行静态类型检查是不够的,例如:
- 当集合传递给第三方库时,库代码必须通过插入错误类型的元素来破坏集合。
- 程序因ClassCastException而失败,表明错误输入的元素已放入参数化集合中。不幸的是,异常可以在插入错误元素之后的任何时间发生,因此它通常提供关于问题的真实来源的很少或没有信息。
大约四年后的2012年7月更新:
现在(2012年)详细介绍"API Migration Compatibility Rules (Signature Test)"
Java编程语言使用擦除来实现泛型,这确保了旧版本和通用版本通常生成相同的类文件,除了有关类型的一些辅助信息。二进制兼容性未被破坏,因为可以使用泛型类文件替换旧类文件,而无需更改或重新编译任何客户端代码。为了便于与非通用遗留代码接口,还可以使用参数化类型的擦除作为类型。这种类型称为原始类型(Java语言规范3 / 4.8)。允许原始类型还可确保源代码的向后兼容性。据此,以下版本的java.util.Iterator类都是二进制和源代码向后兼容:
Class java.util.Iterator as it is defined in Java SE version 1.4:
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
Class java.util.Iterator as it is defined in Java SE version 5.0:
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}