Java Generics:在运行时是否保留了有关generics类型的任何元信息?

背景

我对Javagenerics的理解是它完全是一个编译时function(主要关注类型安全检查)。 任何generics类的类型信息在运行时丢失( 类型擦除 )。

不过,我看到许多框架似乎也在运行时利用了类型信息。 例如,谷歌guice 提供商 。 guice提供程序可以在运行时实例化并提供它的generics类型的新实例。

class Container { @Inject public Container(Provider contentProvider) { //This works at Runtime... but How ??? //When type's are not even preserved at runtime, how does the Provider knows it has to instantiate an object of type 'Content' Content content = contentProvider.get(); } } 

  1. 是否存在与在运行时保留的generics类型相关的任何信息。 ? 如果 ,那什么? 如果 不是 ,那么像google guice这样的库如何在内部运行(上例)

  2. 仿制药比编译时间安全更多吗? 在,有没有任何用例(除了确保编译时安全性),谁可以使用generics获得优势?

当然,支持类通用的信息。

换句话说:当您反编译ArrayList.class时,您会发现有关此类允许一个generics类型参数这一事实的提示。 换句话说:类文件包含信息。 使用reflection可以在运行时检查此元信息。

但是当你有另一个使用一些List对象的类时 – 你没有在编译的类中找到关于“list使用整数”的信息 – 除非你使用一些特定的模式,例如这里所概述的。

所以答案基本上是:对于几乎所有实际相关的用例,“generics”只是编译时间

例:

 public class GenericsExample { private T member; public T foo(T bar) { return member; } } 

现在运行:javap -p -c GenericsExample

 Compiled from "GenericsExample.java" public class GenericsExample { private T member; public GenericsExample(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public T foo(T); Code: 0: aload_0 1: getfield #2 // Field member:Ljava/lang/Object; 4: areturn } 

正如您所看到的,反编译器理解该类使用该generics类型T.有关详细信息,请参阅此处或此处 。

如果类扩展generics类或接口并为参数提供具体类型,则可通过Class.getGenericSuperclass()获得该类型。 该方法将(在这种情况下)返回将包含实际参数化的ParameterizedType。

例如,如果你有:

 class BigIntegerList extends ArrayList {} 

然后你可以这样做:

 Class fooClass = BigIntegerList.class; Type superclass = fooClass.getGenericSuperclass(); if (superclass instanceof ParameterizedType) { ParameterizedType parameterized = (ParameterizedType) superclass; Type[] parameterizations = parameterized.getActualTypeArguments(); System.out.println(Arrays.toString(parameterizations)); // prints: "[class java.math.BigInteger]" } 

这确实被像Guice这样的reflection型图书馆使用。 另一个例子是Jackson的TypeReference ,它可以让你读取一个JSON列表的事物作为BigDecimal列表(例如)。

如果您不知道将要用于特定类的类型,generics是一种很好的编程方式。 在运行时,将根据类的输入设置generics类类型。 它主要用于编译时安全性。

是否存在与在运行时保留的generics类型相关的任何信息。 ? 如果是,那是什么?

保留在已编译类中的单个信息是从擦除后获取的原始对象/变量转换为源代码中用作通用的特定类型。
但这些只依赖于声明的变量类型,而不是所使用的真正generics类型。

因此,在运行时,您无法在没有解决方法的情况下直接访问通用信息,因为在实例化generics类时传递类。

如果不是,那么像谷歌guice这样的图书馆在内部运作(

你错了。
在Guice中这段代码:

  Content content = contentProvider.get(); 

将返回Content的实例,而不是generics类型。 看看文档 :

T get()

提供T的实例。

  1. Java Generics使用称为类型擦除的东西,因此在运行时没有关于该类型的信息。 但是,如果可以某种方式传递类型信息,则可以使用Class.newInstance()方法创建任何类的实例(实际上,这是创建通用数组的唯一方法)

  2. 编译时间安全是generics的主要目标。 但它们通常也可用于编写更简洁的代码,否则这是不可能的

对于详细的处理,我推荐优秀的Java Generics和Collections

通用信息只会持续到编译时。在您的示例中,它在编译时可用。 让我用一个例子解释一下

Public void printObject(list empt){

//这不会显示列表在运行时保留此信息将返回的对象类型。 就业en = empt.get(); }