Java Generics : Is any meta information about the generic type preserved at runtime as well?

独自空忆成欢 提交于 2019-12-07 12:33:45

问题


Background

My understanding of Java generics is it being completely a compile time feature (mainly focusing on type safety checks). The type information for any generic class is lost at runtime (type erasure).

Still, i see many frameworks seem to leverage the type information at runtime as well. For example, google guice Providers. The guice provider can instantiate and provide new instances of it's generic type at runtime.

class Container
{
     @Inject   
     public Container(Provider<Content> 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();   
     }
}

Question

  1. Is there any information related to generic types which is preserved at runtime as well. ? If yes, what ?. If no, than how does libraries like google guice operate internally (Above example)

  2. Is there more to generics than just compile time safety ? As in, is there any use-case (other than ensuring compile time safety) where one would get advantage using generics ?


回答1:


Of course the information that a class is generic is supported.

In other words: when you decompile ArrayList.class you will find hints about the fact that this class allows for one generic type parameter. In other words: class files contain meta information. And using reflection it is possible to inspect this meta information at runtime.

But when you have another class that uses some List<Integer> object - then you do not find information about that "list uses an Integer" in the compiled class - unless you use some specific patterns, as outlined here for example.

So the answer is basically: for almost all use cases of practical relevance, "generics" are compile time only.

Example:

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

Now run: javap -p -c GenericsExample

Compiled from "GenericsExample.java"
public class GenericsExample<T> {
  private T member;

  public GenericsExample();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public T foo(T);
    Code:
       0: aload_0       
       1: getfield      #2                  // Field member:Ljava/lang/Object;
       4: areturn       
}

As you can see the decompiler understands that the class uses that generic type T. For more details see here or there.




回答2:


If a class extends a generic class or interface and provides a concrete type for the parameter, then that type is available via Class.getGenericSuperclass(). That method will (in this case) return a ParameterizedType that will contain the actual parameterization.

For instance, if you have:

class BigIntegerList extends ArrayList<BigInteger> {}

Then you can do:

Class<BigIntegerList> 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]"
}

This is indeed used by reflection-heavy libraries such as Guice. Another example is Jackson's TypeReference, which can let you read a JSON list-of-things as list-of-BigDecimal (for instance).




回答3:


Generics is a good way to program if you don't know what type you're going to be using for a specific class. At runtime, the generic class type will be set based on the input to the class. It's mainly useful for compile time safety.




回答4:


Is there any information related to generic types which is preserved at runtime as well. ? If yes, what ?.

Single information preserved in the compiled class, are casts from raw objects/variables gotten after erasure to the specific types used as generic in the source code.
But these rely just on the declared type of variable, not the real generic type used.

So, at runtime you cannot directly access to the generic information without workaround as passing a class when you instantiate a generic class.

If no, than how does libraries like google guice operate internally (

You are wrong.
In Guice this code :

 Content content = contentProvider.get();   

will return an instance of Content, not the generic type. Look at the documentation :

T get()

Provides an instance of T.




回答5:


  1. Java Generics uses something called type erasure, so no information about the type is available at runtime. It is, however, possible to create an instance of any class using Class.newInstance() method if the type information can be passed somehow (in fact, this is the only way a generic array could be created)

  2. Compile time safety is the primary goal of generics. But they can often be used to write more concise code as well, which would not have been possible otherwise

For a detailed treatment, I recommend the excellent book Java Generics and Collections




回答6:


Generic information only persist till compile time .In your example as well it is available till compile time. Let me explain it with one example

Public void printObject( list empt) {

// This don't shows that list keep this information at runtime that what type of object it will return . Employment en =empt.get(); }



来源:https://stackoverflow.com/questions/45802927/java-generics-is-any-meta-information-about-the-generic-type-preserved-at-runt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!