tra*_*veh 8 java generics type-erasure
我发现了很多关于如何克服这个限制的帖子,但是没有关于为什么存在这种限制的帖子(除了这个,它只是提到它与类型擦除有关).
那么为什么不能创建泛型类型的实例呢?
澄清一下,我的问题不是如何做到的.我知道在C#中有可能,为什么不用Java?我很好奇为什么Java人员没有实现类似的机制?为什么迫使Java开发人员使用可能导致运行时错误的尴尬变通方法?这种机制是否存在潜在的危险?
Ada*_*ker 10
简短回答:
Java是一种编译的编程语言,这意味着您的字节码在运行时是常量.new E()如果E未知,则无法生成字节码.
说明:在运行时擦除通用信息:
public class Container<E> {
private E item;
public E getItem() {return item;}
}
class BoxWithPresent extends Container<Present> {
}
class SimpleBox extends Container {
}
Run Code Online (Sandbox Code Playgroud)
在bytecode类中BoxWithPresent 包含item类型的字段Present,但类SimpleBox包含item类型的字段Object(因为E未指定类型).
现在你编写抽象实例化方法:
public class Container<E> {
public <E> E createE() {
return new E(); // imagine if that was allowed
}
}
Run Code Online (Sandbox Code Playgroud)
这里应该生成什么字节码?.class文件是在编译时生成的,但是我们不知道什么是E类型.
那么......可以new T() 换成new Object()吗?不好的想法,上课BoxWithPresent不喜欢它,因为它期望的E是Present.
可以替换class.newInstance()吗?同样不,class方法范围中没有变量.
这就是为什么new E()不可能的原因.
但是有一些变通方法可以class作为参数传递或提取通用信息.
最简单的答案是在运行时不存在泛型类型参数.
在第5版中,泛型被改进为Java语言.为了保持与现有代码库的向后兼容性,它们是通过擦除实现的.
源代码在编译时存在泛型类型参数,但在编译期间,几乎所有证据都会在字节代码中被删除.之所以选择这种泛型,是因为它保持了前仿制代码和Java 5+通用代码之间的互操作性.因此,通用泛型的类型安全很大程度上只是编译时的现象. 如果您的通用代码编译没有错误且没有警告,那么您可以放心,您的代码是类型安全的.
但是,由于擦除,(从Java 5开始)有两种类型:
可兑现的.例如String,Integer等等.可编译类型在编译时具有与在运行时具有的相同类型信息.
不可兑现.例如List<String>,List<T>,和T.不可重新生成的类型在编译时的运行时具有较少的类型信息.事实上,上述的运行时类型是List,List和Object.在编译期间,擦除泛型类型信息.
您不能将new运算符与不可重新类型一起使用,因为在运行时没有类型安全的方法可以让JVM生成正确类型的对象.
源代码:
T myObject = new T();
Run Code Online (Sandbox Code Playgroud)
以上不编译.在运行时,T已被删除.
规避类型擦除和Java泛型的一些问题的策略是使用类型令牌.此策略在以下创建新T对象的通用方法中实现:
public <T> T newInstance(Class<T> cls) {
T myObject = cls.newInstance();
return myObject;
}
Run Code Online (Sandbox Code Playgroud)
泛型方法从Class作为参数传递的对象中捕获类型信息.此参数称为类型标记.不幸的是,类型标记本身必须始终是可恢复的(因为你不能得到Class一个不可再生类型的对象),这可能会限制它们的用处.
| 归档时间: |
|
| 查看次数: |
11983 次 |
| 最近记录: |