Java 什么是具体泛型?它们如何解决类型擦除问题,为什么不进行重大更改就不能添加它们?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/879855/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:35:16  来源:igfitidea点击:

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

javagenericscollectionsjvmreification

提问by sal

I've read Neal Gafter'sblog on the subject and am still unclear on a number of points.

我已经阅读了Neal Gafter关于这个主题博客,但在很多方面仍然不清楚。

Why is it not possible to create implementations of the Collections API that preserve type information given the current state of Java, the JVM and existing collections API? Couldn't these replace the existing implementations in a future version of Java in a way where backwards compatibility is preserved?

考虑到 Java、JVM 和现有集合 API 的当前状态,为什么不能创建保留类型信息的集合 API 实现?这些不能以保留向后兼容性的方式替换 Java 未来版本中的现有实现吗?

As an example:

举个例子:

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

Where REIList is something like this:

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 ...

And the methods use Object o and Class klass to get the type information.

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

Why would preserving generic class information require language changes rather than just a JVM implementation change?

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

What am I not understanding?

我不明白什么?

采纳答案by ghempton

The whole point is that reified generics have support in the compiler for preserving type information, whereas type erased generics don't. AFAIK, the whole point of having type erasure in the first place was to enable backwards compatibility (e.g. lower versioned JVMs could still understand generic classes).

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

You can explicitly add the type information in the implementation, as you have above, but that requires additional code every time the list is used, and is pretty messy in my opinion. Also, in this case, you still don't have runtime type checking for all of the list methods unless you add the checks yourself, however reified generics will ensure the runtime types.

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

回答by Harper Shelby

IIRC (and based on the link), Java generics are just syntactic sugar for the existing technique of using an Object collection and casting back and forth. It's safer and simpler using the Java generics, since the compiler can do the checks for you to verify that you maintain compile-time type safety. Run time, however, is an entirely different problem.

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

.NET generics, on the other hand, actually create new types - a List<String>in C# is a different type than a List<Int>. In Java, under the covers, they are the same thing - a List<Object>. This means that if you have one of each, you can't look at them at run time and see what they were declared as - only what they are now.

另一方面,.NET 泛型实际上创建了新类型 - List<String>C# 中的 a 与List<Int>. 在 Java 中,在幕后,它们是相同的东西 - List<Object>. 这意味着,如果您拥有其中之一,则无法在运行时查看它们并查看它们的声明内容 - 只能查看它们现在的样子。

The reified generics would change that, giving Java developers the same capabilities that exist now in .NET.

具体化泛型将改变这一点,为 Java 开发人员提供与 .NET 中现有相同的功能。

回答by n3rd

I'm no expert on the subject, but as I understand it the type information is lost at compile time. Unlike in C++, Java does not use a template system, type safety is achieved entirely through the compiler. At runtime, a List is actually a List, always.

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

So my take is that a change in the language specification is required due to the fact that the type information is not available to the JVM because it isn't there.

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

回答by Richard Gomes

Contrary to beliefs of majority of Java developers, it is possible to keep compile-time type information and retrieve this information at runtime, despite in a very restricted way. In other words: Java does provide reified generics in a very restricted way.

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

Regarding type erasure

关于类型擦除

Notice that, at compile-time, the compiler has full type information available but this information is intentionally dropped in generalwhen the binary code is generated, in a process known as type erasure. This is done this way due to compatibility issues: The intention of language designers was providing full source code compatibility and full binary code compatibility between versions of the platform. If it was implemented differently, you would have to recompile your legacy applications when you migrate to newer versions of the platform. The way it was done, all method signatures are preserved (source code compatibility) and you don't need to recompile anything (binary compatibility).

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

Regarding reified generics in Java

关于 Java 中的具体泛型

If you need to keep compile-time type information, you need to employ anonymous classes. The point is: in the very special case of anonymous classes, it is possible to retrieve full compile-time type information at runtime which, in other words means: reified generics.

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

I've written an article about this subject:

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

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

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

In the article, I describe how our users reacted to the technique. In a nutshell, this is an obscure subject and the technique (or the pattern, if you prefer) looks extraneous to majority of Java developers.

在这篇文章中,我描述了我们的用户对这项技术的反应。简而言之,这是一个晦涩的主题,而且该技术(或模式,如果您愿意)对于大多数 Java 开发人员来说似乎是无关紧要的。

Sample code

示例代码

The article I've mentioned above has links to source code which exercises the idea.

我上面提到的文章有链接到练习这个想法的源代码。