什么是Reified Generics?他们如何解决类型擦除问题以及为什么不能在没有重大变化的情况下添加它们?

时间:2009-05-18 21:10:45

标签: java generics collections jvm reification

我已经阅读了关于此主题的Neal Gafter's博客,但我仍然不清楚其中的一些观点。

为什么在给定Java的当前状态,JVM和现有集合API的情况下,无法创建保留类型信息的Collections API的实现?难道这些不能以保留向后兼容性的方式替换未来Java版本中的现有实现吗?

举个例子:

List<T> list = REIList<T>(T.Class);

REIList就是这样:

public REIList<T>() implements List {
  private Object o;
  private Class klass;

  public REIList(Object o) {
    this.o = o;
    klass = o.getClass();
  }
... the rest of the list implementation ...

这些方法使用Object o和Class klass来获取类型信息。

为什么保留泛型类信息需要语言更改而不仅仅是JVM实现更改?

我不理解什么?

4 个答案:

答案 0 :(得分:33)

重点是,具体化的泛型在编译器中支持保留类型信息,而类型擦除泛型不支持。 AFAIK,首先进行类型擦除的重点是启用向后兼容性(例如,较低版本的JVM仍然可以理解泛型类)。

如上所述,您可以在实现中显式添加类型信息,但每次使用列表时都需要额外的代码,而且在我看来非常混乱。此外,在这种情况下,您仍然没有对所有列表方法进行运行时类型检查,除非您自己添加检查,但是确定的泛型将确保运行时类型。

答案 1 :(得分:19)

与大多数Java开发人员的信念相反,尽管采用非常有限的方式,仍可以保留编译时类型信息并在运行时检索此信息。换句话说: Java确实以非常有限的方式提供了具体化的泛型

关于类型擦除

请注意,在编译时,编译器具有可用的完整类型信息,但在生成二进制代码时,在一般称为类型擦除的过程中,有意删除此信息 。由于兼容性问题,这是以这种方式完成的:语言设计者的意图是提供完整的源代码兼容性和平台版本之间的完全二进制代码兼容性。如果以不同方式实现,则在迁移到较新版本的平台时,必须重新编译旧版应用程序。完成它的方式,保留所有方法签名(源代码兼容性),您不需要重新编译任何东西(二进制兼容性)。

关于Java中的具体化泛型

如果需要保留编译时类型信息,则需要使用匿名类。 关键是:在匿名类的非常特殊的情况下,可以在运行时检索完整的编译时类型信息,换句话说,就是:reified generics。

我写了一篇关于这个主题的文章:

http://rgomes-info.blogspot.co.uk/2013/12/using-typetokens-to-retrieve-generic.html

在文章中,我描述了用户对该技术的反应。简而言之,这是一个模糊的主题,而且技术(或模式,如果您愿意)看起来与大多数Java开发人员无关。

示例代码

我上面提到过的文章中有源代码的链接,可以实现这个想法。

答案 2 :(得分:12)

IIRC(并且基于链接),Java泛型只是使用Object集合和来回转换的现有技术的语法糖。使用Java泛型更安全,更简单,因为编译器可以为您进行检查,以验证您是否保持编译 -time类型安全。然而,运行时间是一个完全不同的问题。

另一方面,.NET泛型实际上创建了新类型 - C#中的List<String>List<Int>的类型不同。在Java中,它们是一样的 - List<Object>。这意味着如果你有一个,你不能在运行时查看它们,看看它们被声明为什么 - 只是它们现在是什么。

改进后的泛型会改变这种情况,为Java开发人员提供与.NET现在相同的功能。

答案 3 :(得分:4)

我不是这方面的专家,但据我所知,类型信息在编译时丢失了。与C ++不同,Java不使用模板系统,类型安全性完全通过编译器实现。在运行时,List实际上是一个List,总是。

所以我认为需要更改语言规范,因为JVM 无法使用类型信息,因为它不存在

相关问题