繁体   English   中英

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

[英]What are Reified Generics? How do they solve Type Erasure problems and why can't they be added without major changes?

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

为什么在给定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实现更改?

我不明白的是什么?

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

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

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

关于类型擦除

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

关于Java中的reified通用

如果需要保留编译时类型信息,则需要使用匿名类。 关键是:在匿名类的非常特殊的情况下,可以在运行时检索完整的编译时类型信息,换言之,意思是:具体化的泛型。

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

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

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

示例代码

我上面提到的文章链接到源代码,它实现了这个想法。

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

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

改进后的泛型将改变这一点,为Java开发人员提供与.NET现在相同的功能。

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

所以我的看法是需要更改语言规范,因为类型信息不可用于JVM, 因为它不存在

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM