为什么以下类型在java中是可恢复和不可恢复的?
在计算中,具体化意味着一种类型的显式表示 – 即运行时类型信息。
oracle教程说,
可重新类型是一种类型,其类型信息在运行时完全可用。 这包括基元,非generics类型,原始类型和未绑定通配符的调用。
不可再生类型是在编译时通过类型擦除删除信息的类型 – 未定义为无界通配符的generics类型的调用。
如果类型是以下之一,则类型是可以恢复的:
- 一个原始类型(如
int
)//理解- 非参数化类或接口类型(例如
Number
,String
或Runnable
)//为什么- 一种参数化类型,其中所有类型参数都是无界通配符(例如
List
,ArrayList
或Map
)//为什么- 原始类型(如
List
,ArrayList
或Map
)//为什么- 组件类型可以重新生成的数组(例如
int[]
,Number[]
,List[]
,List[]
或int[][]
)//为什么
如果类型是以下之一,则该类型不可再生:
- 类型变量(如
T
)//为什么- 具有实际参数的参数化类型(例如
List
,ArrayList
或Map
)//为什么- 带有绑定的参数化类型(例如
List
或Comparable
)//为什么
为什么2,3,4,5是可以再生的,6,7,8是不可再生的?
Sun / Oracle说原因是需要的组合(编译时类型检查就足够了),代码大小(避免类似STL的代码膨胀)和性能(避免在运行时已经在编译时完成的类型检查):
类型擦除确保不为参数化类型创建新类; 因此,generics不会产生运行时开销。
简而言之,1-6是可以恢复的,因为它们只是保持与代码中指定的相同类型,因此没有类型信息丢失/删除,但7-9将在编译期间丢失类型信息(<>之间的东西)所以可以不能在运行时访问。
你可以问谷歌同样的问题:
可再生型
当您使用generics时,大多数情况下,编译时类型信息都会丢失。 在运行时,通常所有程序都知道引用是对某种Object的引用。 如果在运行时也知道所有类型信息,则该类型称为可恢复。 也许有一天将会重新设计generics,以便所有类型都可以恢复。
可重新类型是一种类型,其类型信息在运行时完全可用。 这包括基元,非generics类型,原始类型和未绑定通配符的调用。
不可再生类型是在编译时通过类型擦除删除信息的类型 – 未定义为无界通配符的generics类型的调用。 不可重新生成的类型在运行时没有提供所有信息。 不可重定义类型的示例是List
和List ; JVM无法在运行时区分这些类型。 如“generics限制”中所示,某些情况下无法使用不可重新生成的类型:例如,在表达式的实例中,或作为数组中的元素。
参考
理解这两个术语的含义。
可恢复意味着其类型在运行时完全可用意味着java编译器不需要任何类型擦除过程。
Non-Reifiable意味着java编译器需要类型擦除过程,因为类型不完全可用。
如果类型是以下之一,则类型是可以恢复的:
1.基本类型(如int):
这里认为当你编写或使用任何int作为参考时,你认为编译器需要任何进程来识别int的类型吗? 不,因为int是int ….对于所有原始类型都是相同的
2.非参数化类或接口类型(例如Number,String或Runnable)
我在前面的回答中告诉他的相同的答案,编译器不需要任何类型擦除Number,String或Runnable。
3.参数化类型,其中所有类型参数都是无界通配符(例如List <?>,ArrayList <?>或Map <?,?>)
所有无界通配符都被接受为可再生类型,因为在可再生类型的定义中已经提到过,现在由API开发人员将其视为可再生类型。
4.原始类型(例如List,ArrayList或Map)::
与第一个问题相同的答案
5.一个组件类型可以重新生成的数组(例如int [],Number [],List <?> [],List []或int [] [])::
与第一个问题相同的答案
如果类型是以下之一,则该类型不可再生:
6.类型变量(如T):
因为java无法识别T的类型,所以编译器需要类型擦除来识别类型。
7.具有实际参数的参数化类型(例如List
这里所有类型都是generics类型,在运行时编译器中将List列为List …因此根据Non-refiable的定义,所有这些集合都被认为是不可恢复的。
8.带有绑定的参数化类型(例如List <?extends Number>或Comparable <?super String>)。
与前一个答案相同
Java最初在1.1版中实现了reflection。
在5.0版中引入了通用类。
在引入generics时,决定出于向后兼容性的原因,generics类型信息将在运行时被擦除。 这允许编写前generics的代码在没有修改的情况下使用基于generics的代码进行操作。
例如, List[Integer32]
将由编译器转换为Integer32[]
。 所有类型检查都将在编译时完成,如果遗漏了任何内容,则会产生运行时错误。
此实现细节意味着generics未被实现(VM中没有特定的实现),因此无论何时尝试反映generics类型,返回的信息都将是基础类型的信息。 这将是有利的另一个原因是因为无论何时使用,都不必由VM发出具体类型的实现(例如,在c#中,无论何时使用generics类型,它的实际实现都是由VM在运行时生成的,以及reflection元数据,因此每当需要生成新类型时都会有性能损失。
只是一个有根据的猜测,但我怀疑理解这一点的关键是要认识到,虽然Java是一种强类型语言并且validation类型引用是编译过程的一部分,但在许多情况下,实际上并不需要类型信息来执行逻辑。 在这种情况下,生成的字节码可能知道它正在使用Object的实例,但不知道类型。 鉴于不使用强类型的语言可以生成为java字节码,这尤其有意义。 因此,如果删除了对象类型,则该实例将是不可恢复的。
我不完全确定我理解你的问题,但你可能指的是对象类型而不是原始类型。 这个问题更为重要,因为诸如int或double之类的原始类型不能用作generics类型 – 因此它们的包装类如Integer。
// This won't work ArrayList list = new ArrayList (); // But this will ArrayList list = new ArrayList ();
总结一下,我会说所有对象 – 只有对象 – 是可以恢复的。 (因此可用作generics类型实例化)