在关于反射的本教程中,它指出:
[…]因为泛型是通过类型擦除实现的,因此在编译过程中会删除有关泛型类型的所有信息
我的知识是使用泛型,以便在编译时编译器可以检查类型安全性。即失败快速方法。但是该链接提到类型擦除会在编译期间删除通用信息。
您引用的语句是正确的:编译器在编译过程中在内部使用通用类型信息,在处理源时会生成与类型相关的错误。然后,一旦完成验证,编译器将生成类型擦除的字节码,所有对泛型类型的引用都将替换为它们各自的类型擦除。
当您通过反射观察类型时,这一事实变得显而易见:所有接口,类和函数都变为非泛型,所有与泛型类型参数绑定的类型都将根据源中指定的泛型类型约束替换为非泛型类型码。尽管反射API确实提供了在运行时访问与泛型*相关的某些信息的规定,但是当您通过反射访问类时,虚拟机无法检查确切的泛型类型的兼容性。
例如,如果您将类型的类成员List<String>
设为type 并尝试将其设置为type
List<Integer>
,则编译器将抱怨。但是,如果您尝试通过反射进行相同的操作,则编译器将无法发现,并且代码将在运行时失败,其方式与没有泛型时相同:
class Test {
private List<String> myList;
public void setList(List<String> list) {
myList = list;
}
public void showLengths() {
for (String s : myList) {
System.out.println(s.length());
}
}
}
...
List<Integer> doesNotWork = new ArrayList<Integer>();
doesNotWork.add(1);
doesNotWork.add(2);
doesNotWork.add(3);
Test tst = new Test();
tst.setList(doesNotWork); // <<== Will not compile
Method setList = Test.class.getMethod("setList", List.class);
setList.invoke(tst, doesNotWork); // <<== This will work;
tst.showLengths(); // <<== However, this will produce a class cast exception
ideone上的演示。
当我从Eclipse构建到maven构建时,我发现了项目中的许多问题。我使用2.5.1编译器插件。 JDK是开放的-JDK-7 我在一个新项目中隔离了这个问题,并对其进行了深入研究。问题是: 这无法使用javaC进行编译(但在Eclipse中工作),并说明以下错误: [错误]无法执行目标组织。阿帕奇。专家插件:maven编译器插件:2.5.1:项目测试时编译(默认编译):编译失败 [错误]/hom
Groovy中的简单泛型类 Groovy版本: 这是我做的一个简单的测试用例,当一个更复杂的类不能编译时,错误是“不能将类型T的值赋给类型double[]的变量”。
问题内容: 有三种方法可以实现泛型: 只是用于编译时间检查的工具,但是每个模板实例都被编译为相同的字节/汇编代码实现(如注释“类型擦除”实现中所述的Java) 每个模板实例均被编译为专用代码(C ++,C#) #1和#2的组合 在Swift中实现哪一个? 问题答案: Swift首先会编译一个执行动态类型检查的实现,但是当速度与代码大小之间的权衡是有意义的时候,优化器可以选择为特定类型克隆专门的实现
我想在编译时向某些类添加一个泛型字段。为了实现这个目标,我按照官方文档实现了我自己的 AST 注释和转换类,并使用 AST 注释注释了所需的类。 但是我在编译时得到了这个错误: org . codehaus . groovy . control . multiplecompilationerrorsexception:启动失败:/home/.../groovy/Sample.groovy: -1:
问题内容: 我不得不发现我的项目中有Java代码,该代码可以在Eclipse中编译并正常运行,但是会在javac中引发编译错误。 一个完整的代码段: javac中的编译返回: 现在,此错误阻止在Maven中构建项目。由于Eclipse编译器具有更高的容忍度,因此我现在不得不假设代码段的定义和用法如上所述,静态方法不是有效的Java吗? 问题答案: 似乎Sun的1.6 JDK无法推断正确的类型。以下