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

时间:2013-09-17 11:39:20

标签: java generics type-erasure

  

在计算中,具体化意味着一种明确的表现形式   一种类型 - 即运行时类型信息。

oracle tutorials说,

  

可再生类型是类型信息完全可用的类型   在运行时。这包括原语,非泛型类型,原始类型,   和未绑定的通配符的调用。

     

不可再生类型是已删除信息的类型   按类型擦除编译时 - 对泛型类型的调用   未定义为无界通配符。

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

  
      
  1. 原始类型(例如int)//理解
  2.   
  3. 非参数化类或接口类型(例如NumberStringRunnable)//为什么
  4.   
  5. 参数化类型,其中所有类型参数都是无界通配符(例如List<?>ArrayList<?>Map<?, ?>)//为什么
  6.   
  7. 原始类型(例如ListArrayListMap)//为什么
  8.   
  9. 其组件类型可以恢复的数组(例如int[]Number[]List<?>[]List[]int[][])// why
  10.   

如果类型是以下之一,则该类型无法恢复:

  
      
  1. 类型变量(例如T)//为什么
  2.   
  3. 包含实际参数的参数化类型(例如List<Number>ArrayList<String>Map<String, Integer>)//为什么
  4.   
  5. 带有绑定的参数化类型(例如List<? extends Number>Comparable<? super String>)//为什么
  6.   

为什么2,3,4,5是可以恢复的,6,7,8是不可恢复的?

7 个答案:

答案 0 :(得分:11)

Sun/Oracle says原因是需要的组合(编译时类型检查就足够了),代码大小(避免类似STL的代码膨胀)和性能(避免在运行时已经在编译时完成的类型检查):< / p>

  

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

简而言之,1-5是可以恢复的,因为它们只是保持与代码中指定的相同类型,因此没有丢失/删除类型信息,但是6-8将在编译期间丢失类型信息(&lt; &gt;)所以无法在运行时访问。

答案 1 :(得分:8)

理解这两个术语的含义。

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

不可恢复表示java编译器需要类型擦除过程,因为类型不完全可用。

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

<强> 1。基本类型(如int):

这里认为当你编写或使用任何int作为引用时,你认为编译器需要任何进程来识别int的类型吗?不,因为int是int ....对于所有原始类型都是相同的

<强> 2。非参数化类或接口类型(例如Number,String或Runnable)

我在之前的回答中说过,答案是编译器不需要对Number,String或Runnable进行任何类型的擦除。

第3。一种参数化类型,其中所有类型参数都是无界通配符(例如List&lt;?&gt;,ArrayList&lt;?&gt ;,或Map&lt;?,?&gt;)

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

<强> 4。原始类型(如List,ArrayList或Map)::

与第一个问题相同的答案

<强> 5。组件类型可以重新生成的数组(例如int [],Number [],List&lt;?&gt; [],List []或int [] [])::

与第一个问题相同的答案

如果类型是以下之一,则该类型无法恢复:

<强> 6。类型变量(例如T):

由于java无法识别T的类型,因此编译器需要键入擦除来识别类型。

<强> 7。具有实际参数的参数化类型(例如List&lt; Number&gt;,ArrayList&lt; String&gt;或Map&lt; String,Integer&gt;):

此处所有类型都是泛型类型,在运行时编译器中将List列为List ...因此根据Non-refiable的定义,所有这些集合都被认为是不可恢复的。

<强> 8。带有边界的参数化类型(例如List&lt;?extends Number&gt;或Comparable&lt;?super String&gt;)。

与前一个相同的答案

答案 2 :(得分:7)

你可以向google问同样的问题:

可再生类型

  

当你使用泛型时,很多时候都是编译时类型   信息丢失了。在运行时,通常所有程序都知道a   引用是对某种Object的引用。如果全部   类型信息在运行时也是已知的,类型被调用   reifiable。也许有一天,仿制药将被重新设计以便所有人   类型是可以回收的。

答案 3 :(得分:7)

  

可再生类型是类型信息完全可用的类型   在运行时。这包括原语,非泛型类型,原始类型,   和未绑定的通配符的调用。

     

不可再生类型是已删除信息的类型   按类型擦除编译时 - 对泛型类型的调用   未定义为无界通配符。不可重复的类型没有   它在运行时可用的所有信息。不可再生的例子   类型是List&lt; String&gt;和列表&lt; Number&gt ;; JVM说不清楚   运行时这些类型之间的差异。如限制所示   泛型,在某些情况下,非可再生类型   不能使用:例如,在表达式的实例中,或作为   数组中的元素。

Reference

答案 4 :(得分:1)

Java最初在​​1.1版中实现了反射。

在5.0版本中引入了通用类。

在介绍泛型时,决定出于向后兼容性的原因,泛型类型信息将在运行时被删除。这允许使用泛型编写的代码在没有修改的情况下使用基于泛型的代码进行操作。

例如,编译器会将List[Integer32]翻译为Integer32[]。 所有类型检查都将在编译时完成,如果遗漏了任何内容,则会产生运行时错误。

此实现细节意味着泛型未被实现(VM中没有特定的实现),因此无论何时尝试反映泛型类型,返回的信息都将是基础类型的信息。这将是有利的另一个原因是因为无论何时使用,都不必由VM发出具体类型的实现(例如,在c#中,无论何时使用泛型类型,它的实际实现都是由VM在运行时生成的,以及反射元数据,因此每当需要生成新类型时都会有性能损失。)

答案 5 :(得分:0)

只是一个有根据的猜测,但我怀疑理解这一点的关键是要认识到,虽然Java是一种强类型语言并且验证类型引用是编译过程的一部分,但在许多情况下,实际上并不需要执行类型信息逻辑。在这种情况下,生成的字节码可能知道它正在使用Object的实例,但不知道类型。鉴于不使用强类型的语言可以生成为java字节码,这尤其有意义。因此,如果删除了对象类型,则该实例将是不可恢复的。

答案 6 :(得分:-1)

我不完全确定我理解你的问题,但你可能指的是对象类型而不是原始类型。这个问题更为重要,因为诸如int或double之类的原始类型不能用作泛型类型 - 因此它们的包装类如Integer。

// This won't work
ArrayList<int> list = new ArrayList<int>();
// But this will
ArrayList<Integer> list = new ArrayList<Integer>();

总结一下,我会说所有对象 - 以及对象 - 都是可以恢复的。 (因此可用作泛型类型实例化)