Get generic type of class at runtime

后端 未结 26 2509
野的像风
野的像风 2020-11-21 04:40

How can I achieve this?

public class GenericClass
{
    public Type getMyType()
    {
        //How do I return the type of T?
    }
}
相关标签:
26条回答
  • 2020-11-21 04:58

    Here is my solution

    public class GenericClass<T>
    {
        private Class<T> realType;
    
        public GenericClass() {
            findTypeArguments(getClass());
        }
    
        private void findTypeArguments(Type t) {
            if (t instanceof ParameterizedType) {
                Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments();
                realType = (Class<T>) typeArgs[0];
            } else {
                Class c = (Class) t;
                findTypeArguments(c.getGenericSuperclass());
            }
        }
    
        public Type getMyType()
        {
            // How do I return the type of T? (your question)
            return realType;
        }
    }
    

    No matter how many level does your class hierarchy has, this solution still works, for example:

    public class FirstLevelChild<T> extends GenericClass<T> {
    
    }
    
    public class SecondLevelChild extends FirstLevelChild<String> {
    
    }
    

    In this case, getMyType() = java.lang.String

    0 讨论(0)
  • 2020-11-21 05:00

    This is my solution:

    import java.lang.reflect.Type;
    import java.lang.reflect.TypeVariable;
    
    public class GenericClass<T extends String> {
    
      public static void main(String[] args) {
         for (TypeVariable typeParam : GenericClass.class.getTypeParameters()) {
          System.out.println(typeParam.getName());
          for (Type bound : typeParam.getBounds()) {
             System.out.println(bound);
          }
        }
      }
    }
    
    0 讨论(0)
  • 2020-11-21 05:00

    Here's one way, which I've had to use once or twice:

    public abstract class GenericClass<T>{
        public abstract Class<T> getMyType();
    }
    

    Along with

    public class SpecificClass extends GenericClass<String>{
    
        @Override
        public Class<String> getMyType(){
            return String.class;
        }
    }
    
    0 讨论(0)
  • 2020-11-21 05:03

    Java generics are mostly compile time, this means that the type information is lost at runtime.

    class GenericCls<T>
    {
        T t;
    }
    

    will be compiled to something like

    class GenericCls
    {
       Object o;
    }
    

    To get the type information at runtime you have to add it as an argument of the ctor.

    class GenericCls<T>
    {
         private Class<T> type;
         public GenericCls(Class<T> cls)
         {
            type= cls;
         }
         Class<T> getType(){return type;}
    }
    

    Example:

    GenericCls<?> instance = new GenericCls<String>(String.class);
    assert instance.getType() == String.class;
    
    0 讨论(0)
  • 2020-11-21 05:04

    I dont think you can, Java uses type erasure when compiling so your code is compatible with applications and libraries that were created pre-generics.

    From the Oracle Docs:

    Type Erasure

    Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:

    Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods. Insert type casts if necessary to preserve type safety. Generate bridge methods to preserve polymorphism in extended generic types. Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.

    http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

    0 讨论(0)
  • 2020-11-21 05:04

    Just in case you use store a variable using the generic type you can easily solve this problem adding a getClassType method as follows:

    public class Constant<T> {
      private T value;
    
      @SuppressWarnings("unchecked")
      public Class<T> getClassType () {
        return ((Class<T>) value.getClass());
      }
    }
    

    I use the provided class object later to check if it is an instance of a given class, as follows:

    Constant<?> constant = ...;
    if (constant.getClassType().equals(Integer.class)) {
        Constant<Integer> integerConstant = (Constant<Integer>)constant;
        Integer value = integerConstant.getValue();
        // ...
    }
    
    0 讨论(0)
提交回复
热议问题