Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 什么是具体化的泛型?他们如何解决类型擦除问题,为什么';它们不能在没有重大变化的情况下添加吗?_Java_Generics_Collections_Jvm_Reification - Fatal编程技术网

Java 什么是具体化的泛型?他们如何解决类型擦除问题,为什么';它们不能在没有重大变化的情况下添加吗?

Java 什么是具体化的泛型?他们如何解决类型擦除问题,为什么';它们不能在没有重大变化的情况下添加吗?,java,generics,collections,jvm,reification,Java,Generics,Collections,Jvm,Reification,我读过关于这个主题的博客,但仍不清楚其中的几点 鉴于Java、JVM和现有集合API的当前状态,为什么不可能创建保留类型信息的集合API实现?难道这些不能以保留向后兼容性的方式取代Java未来版本中的现有实现吗 例如: List<T> list = REIList<T>(T.Class); List List=REIList(T.Class); REIList是这样的: public REIList<T>() implements List { pri

我读过关于这个主题的博客,但仍不清楚其中的几点

鉴于Java、JVM和现有集合API的当前状态,为什么不可能创建保留类型信息的集合API实现?难道这些不能以保留向后兼容性的方式取代Java未来版本中的现有实现吗

例如:

List<T> list = REIList<T>(T.Class);
List List=REIList(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 ...
public REIList()实现列表{
私人客体o;
私家级卡拉斯;
公共资源清单(对象o){
这个。o=o;
klass=o.getClass();
}
…列表实现的其余部分。。。
这些方法使用对象o和类klass来获取类型信息

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


我不明白什么?

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

正如上面所述,您可以在实现中显式地添加类型信息,但是每次使用列表时都需要额外的代码,我认为这是非常混乱的。此外,在这种情况下,除非您自己添加检查,否则您仍然没有对所有列表方法进行运行时类型检查,但是会出现具体化的泛型e运行时类型。

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

另一方面,.NET泛型实际上创建了新的类型—C中的
List
,与
List
不同。在Java中,在封面下,它们是相同的—a
List
。这意味着,如果您拥有每种类型中的一种,则无法在运行时查看它们并查看它们被声明为什么—只能查看它们现在是什么


泛化的泛型将改变这一点,给Java开发者提供了现在.NET中的相同能力.< /p> < p>我不是这个学科的专家,但我理解在编译时丢失了类型信息。不像C++,java不使用模板系统,类型安全完全是通过java实现的。实际上是一张清单,永远


因此,我认为需要对语言规范进行更改,因为JVM无法获得类型信息,因为它不在那里。

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

关于类型擦除 请注意,在编译时,编译器有完整的类型信息可用,但通常在生成二进制代码时,在一个称为类型擦除的过程中故意删除此信息。由于兼容性问题,采用这种方式进行此操作:语言设计人员的目的是提供完整的源代码兼容性和完整性l平台版本之间的二进制代码兼容性。如果采用不同的实现方式,则在迁移到较新版本的平台时,必须重新编译遗留应用程序。按照这种方式,保留所有方法签名(源代码兼容性),并且无需重新编译任何内容(二进制兼容性)

关于Java中的具体化泛型 如果需要保留编译时类型信息,则需要使用匿名类。 要点是:在匿名类的非常特殊的情况下,可以在运行时检索完整的编译时类型信息,换句话说,这意味着:具体化的泛型

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

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

示例代码
我上面提到的这篇文章有一些链接,指向实现这一想法的源代码。

它是为旧JVM编写的源代码和目标代码,可以在新JVM上运行,而不需要任何更改(源代码将“enum”作为标识符存在问题,但这不是泛型本身)。“低版本JVM仍然可以理解泛型类”我把你的列表放在反引号中,这样类型就会显示出来。@David-谢谢。我为其他人做过很多次,你认为我会记得……你可以用匿名类模拟某种具体化的泛型,即:在这种情况下,类型信息在运行时可用。尽管可以这样做,但它的适用性非常有限,而且技术是非常棘手的。经过修饰的泛型是一个很大的失误;这是肯定的。在大多数情况下,除了匿名类,这是正确的。我的意思是:当你使用匿名类时,你可以避免类型擦除。对这个主题要更具体一些:Java不会生成代码的多个副本,比如C++对模板的复制。java java在使用对象的被调用方站点上生成单个副本。因此,尽管在匿名类的情况下运行时类型信息可用,但这就是所有信息:信息本身。字节码不针对运行时将传递的实际类型。这与reif无关