Java generics - obtaining actual type of generic parameter

后端 未结 3 908
遇见更好的自我
遇见更好的自我 2020-12-12 01:14

I have read Get type of a generic parameter in Java with reflection post and it made me wonder how that would be possible. I used the solution that someone posted and using

相关标签:
3条回答
  • 2020-12-12 01:40

    The method you described does ONLY work, when the Generic Type is Set due to inheritance, because then its known during compile time:

     public class SomeClass<T>{
    
     }
    
     public class SpecificClass extends SomeClass<String>{
    
     }
    

    For this example, you can use the method and you'll get back "String.class".

    If you are creating instances on the fly it won't work:

    SomeClass s = new SomeClass<String>(); //wont work here.
    

    Some common work around is, to pass the actual class as a parameter for later reference:

     public class SomeClass<T>{
        Class<T> clazz
    
        public SomeClass(Class<T> clazz){
            this.clazz = clazz;
        }
    
        public Clazz<T> getGenericClass(){
           return this.clazz;
        } 
     }
    

    usage:

     SomeClass<String> someClass= new SomeClass<String>(String.class);
    
     System.out.println(someClass.getGenericClass()) //String.class
    

    Actually you don't even need the Generic type for such an scenario, because Java would do the same thing, as if you would handle the "T" as Object. Only advantage is, that you can define getter and Setter of T and don't need to typecast Objects all the time. (Because Java is doing that for you) (It's called Type Erasure)

    0 讨论(0)
  • 2020-12-12 01:47

    The code you use only works in some very specific cases, where the actual type parameter is known (and stored) at compile time.

    For example if you did this:

    class IntegerList extends ArrayList<Integer> {}
    
    List<Integer> l = new IntegerList();
    

    In this case the code you showed would actually return Integer.class, because Integer is "baked into" the IntegerList.

    Some libraries (ab)use this trick via the use of type tokens. See for example the GSON class TypeToken:

    Represents a generic type T. You can use this class to get the generic type for a class. > For example, to get the generic type for Collection<Foo>, you can use:

    Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
    

    This works because the anonymous class created in here has compiled-in the information that its type parameter is Collection<Foo>.

    Note that this would not work (even if the TypeToken class wouldn't prevent it by making its constructor protected):

    Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>().getType()
    
    0 讨论(0)
  • 2020-12-12 01:49

    The javadoc will tell you what you are doing.

    Class#getGenericSuperclass() states

    Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by this Class.

    If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code. [...]

    The direct superclass of ArrayList is AbstractList. The declaration is as such in the source code

    public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    

    So if you print out the Type object returned by it, you will see

    java.util.AbstractList<E>
    

    and therefore ParameterizedType#getActualTypeArguments() which states

    Returns an array of Type objects representing the actual type arguments to this type.

    will return the Type

    E
    

    since E is the actual type argument used in the ArrayList class definition.

    0 讨论(0)
提交回复
热议问题