为什么以下类型在java中是可恢复和不可恢复的?

在计算中,具体化意味着一种类型的显式表示 – 即运行时类型信息。

oracle教程说,

可重新类型是一种类型,其类型信息在运行时完全可用。 这包括基元,非generics类型,原始类型和未绑定通配符的调用。

不可再生类型是在编译时通过类型擦除删除信息的类型 – 未定义为无界通配符的generics类型的调用。

如果类型是以下之一,则类型是可以恢复的:

  1. 一个原始类型(如int )//理解
  2. 非参数化类或接口类型(例如NumberStringRunnable )//为什么
  3. 一种参数化类型,其中所有类型参数都是无界通配符(例如ListArrayListMap )//为什么
  4. 原始类型(如ListArrayListMap )//为什么
  5. 组件类型可以重新生成的数组(例如int[]Number[]List[]List[]int[][] )//为什么

如果类型是以下之一,则该类型不可再生:

  1. 类型变量(如T )//为什么
  2. 具有实际参数的参数化类型(例如ListArrayListMap )//为什么
  3. 带有绑定的参数化类型(例如ListComparable )//为什么

为什么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 ,ArrayList 或Map

这里所有类型都是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类型实例化)