为什么以下类型在java中是reifiable和non-reifiable的?

2022-09-01 02:09:56

在计算中,重新化已经意味着某种类型的显式表示形式,即运行时类型信息。

预言机教程说,

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

不可重用类型是在编译时通过类型擦除(未定义为无界通配符的泛型类型的调用)删除信息的类型。

如果某个类型是下列类型之一,则该类型是可重用的:

  1. 基元类型(如) //理解int
  2. 非参数化类或接口类型(如 、 、 或 ) // 为什么NumberStringRunnable
  3. 一种参数化类型,其中所有类型参数都是无界通配符(如 、 、 或 ) // whyList<?>ArrayList<?>Map<?, ?>
  4. 原始类型(如 、 、 或 ) // 为什么ListArrayListMap
  5. 组件类型可重用的数组(如 、、、或) // whyint[]Number[]List<?>[]List[]int[][]

如果某个类型是下列类型之一,则该类型不可重试:

  1. 类型变量(如) // whyT
  2. 具有实际参数(如 、 、 或 ) 的参数化类型 // whyList<Number>ArrayList<String>Map<String, Integer>
  3. 具有绑定(如 or)的参数化类型 // whyList<? extends Number>Comparable<? super String>

为什么 2,3,4,5 是可再生的,而 6,7,8 是不可重现的?


答案 1

Sun/Oracle说,原因是以下几种组合:

  • 需要:编译时类型检查是否足够
  • 代码大小:避免类似STL的代码膨胀
  • 性能:避免在运行时进行类型检查,而编译时已经完成了

类型擦除确保不会为参数化类型创建新类;因此,泛型不会产生运行时开销。

简而言之,1-5 是可重用的,因为它们只是保持与代码中指定的类型相同的类型,因此不会丢失/擦除类型信息,但是 6-8 在编译期间会丢失类型信息(<>之间的内容),因此无法在运行时访问。


答案 2

理解这两个术语的含义。

Reifiable意味着其类型在运行时完全可用,这意味着java编译器不需要任何类型擦除过程。

不可重用意味着java编译器需要类型擦除过程,因为类型不完全可用。

如果某个类型是下列类型之一,则该类型是可重用的:

1. 基元类型(如 int):

这里认为,当您编写或使用任何int作为引用时,您是否认为编译器需要任何进程来识别int的类型?否,因为 int 是 int....所有基元类型都相同

2. 非参数化类或接口类型(如数字、字符串或可运行)

与我在上一个答案中告诉的答案相同,编译器不需要对Number,String或Runnable进行任何类型擦除。

3. 一种参数化类型,其中所有类型参数都是无界通配符(如 List<?>、ArrayList<?> 或 Map<?, ?>)

所有无界通配符都被接受为可重用类型,因为它已经在可重用类型的定义中提到,现在由API开发人员决定为什么将其视为可重用类型。

4. 原始类型(如 List、ArrayList 或 Map):

答案与第一个问题相同

5. 组件类型可重用的数组(例如 int[]、Number[]、List<?>[]、List[]或 int[][]) ::

答案与第一个问题相同

如果某个类型是下列类型之一,则该类型不可重试:

6. 类型变量(如 T):

因为java不能识别T的类型,编译器需要类型擦除来识别类型。

7. 具有实际参数的参数化类型(例如 List<Number>、ArrayList<String> 或 Map<String、Integer>)

这里所有类型都是泛型类型,在运行时编译器上,请参阅列表作为列表...因此,根据不可回收的定义,所有这些集合都被视为不可回收的。

8. 具有边界的参数化类型(如 List<? 扩展了 Number> 或Compable<? super String>)。

与上一个相同的答案


推荐