首页 文章

在运行时获取泛型类

提问于
浏览
405

我怎样才能做到这一点?

public class GenericClass<T>
{
    public Type getMyType()
    {
        //How do I return the type of T?
    }
}

到目前为止我尝试的所有东西总是返回 Object 类型而不是使用的特定类型 .

23 回答

  • 12

    如果您使用泛型类型存储变量,您可以轻松解决此问题,添加getClassType方法,如下所示:

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

    我稍后使用提供的类对象来检查它是否是给定类的实例,如下所示:

    Constant<?> constant = ...;
    if (constant.getClassType().equals(Integer.class)) {
        Constant<Integer> integerConstant = (Constant<Integer>)constant;
        Integer value = integerConstant.getValue();
        // ...
    }
    
  • 19

    我发现这是一个简单易懂且易于解释的解决方案

    public class GenericClass<T> {
    
        private Class classForT(T...t) {
            return t.getClass().getComponentType();
        }
    
        public static void main(String[] args) {
            GenericClass<String> g = new GenericClass<String>();
    
            System.out.println(g.classForT());
            System.out.println(String.class);
        }
    }
    
  • -1

    这是我的解决方案:

    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);
          }
        }
      }
    }
    
  • 82

    我认为还有另一种优雅的解决方案 .

    你想要做的是(安全地)将通用类型参数的类型从concerete类“传递”到超类 .

    如果您允许自己将类类型视为类上的“元数据”,则表明在运行时编码元数据的Java方法:注释 .

    首先在这些行中定义自定义注释:

    import java.lang.annotation.*;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface EntityAnnotation {
        Class entityClass();
    }
    

    然后,您必须将注释添加到子类中 .

    @EntityAnnotation(entityClass =  PassedGenericType.class)
    public class Subclass<PassedGenericType> {...}
    

    然后,您可以使用此代码获取基类中的类类型:

    import org.springframework.core.annotation.AnnotationUtils;
    .
    .
    .
    
    private Class getGenericParameterType() {
        final Class aClass = this.getClass();
        EntityAnnotation ne = 
             AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class);
    
        return ne.entityClass();
    }
    

    这种方法的一些局限性是:

    • 您在两个位置指定泛型类型( PassedGenericType )而不是非DRY的一个 .

    • 只有在可以修改具体子类时才可以这样做 .

  • 2

    你不能 . 如果向类中添加类型为T的成员变量(您甚至不必初始化它),则可以使用它来恢复类型 .

  • 0

    你当然可以 .

    出于向后兼容性原因,Java不会在运行时使用该信息 . 但是信息实际上是作为元数据出现的,可以通过反射访问(但它仍然不用于类型检查) .

    从官方API:

    http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29

    However ,对于您的场景,我不会使用反射 . 我个人更倾向于将其用于框架代码 . 在你的情况下,我只是添加类型作为构造函数参数 .

  • 7

    要完成这里的一些答案,我必须得到参数化的MyGenericClass类型,无论层次结构有多高,借助递归:

    private Class<T> getGenericTypeClass() {
            return (Class<T>) (getParametrizedType(getClass())).getActualTypeArguments()[0];
    }
    
    private static ParameterizedType getParametrizedType(Class clazz){
        if(clazz.getSuperclass().equals(MyGenericClass.class)){ // check that we are at the top of the hierarchy
            return (ParameterizedType) clazz.getGenericSuperclass();
        } else {
            return getParametrizedType(clazz.getSuperclass());
        }
    }
    
  • 7

    这是我的诀窍:

    public class Main {
    
        public static void main(String[] args) throws Exception {
    
            System.out.println(Main.<String> getClazz());
    
        }
    
        static <T> Class getClazz(T... param) {
    
            return param.getClass().getComponentType();
        }
    
    }
    
  • 32

    Java泛型主要是编译时,这意味着类型信息在运行时丢失 .

    class GenericCls<T>
    {
        T t;
    }
    

    将编译成类似的东西

    class GenericCls
    {
       Object o;
    }
    

    要在运行时获取类型信息,您必须将其添加为ctor的参数 .

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

    例:

    GenericCls<?> instance = new GenericCls<String>(String.class);
    assert instance.getType() == String.class;
    
  • 47

    这种驾驶室的一个简单解决方案如下所示

    public class GenericDemo<T>{
        private T type;
    
        GenericDemo(T t)
        {
            this.type = t;
        }
    
        public String getType()
        {
            return this.type.getClass().getName();
        }
    
        public static void main(String[] args)
        {
            GenericDemo<Integer> obj = new  GenericDemo<Integer>(5);
            System.out.println("Type: "+ obj.getType());
        }
    }
    
  • 3
    public abstract class AbstractDao<T> <br>
    {
    
        private final Class<T> persistentClass;
    
    
        public AbstractDao()
        {
            this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
                    .getActualTypeArguments()[0];
        }
    }
    
  • 217

    我使用了以下方法:

    public class A<T> {
    
        protected Class<T> clazz;
    
        public A() {
            this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
    
        public Class<T> getClazz() {
            return clazz;
        }
    }
    
    public class B extends A<C> {
       /* ... */
        public void anything() {
           // here I may use getClazz();
        }
    }
    
  • 2

    我见过这样的事情

    private Class<T> persistentClass;
    
    public Constructor() {
        this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                                .getGenericSuperclass()).getActualTypeArguments()[0];
     }
    

    hibernate GenericDataAccessObjects示例中

  • 5

    我不认为你可以,Java在编译时使用类型擦除,因此你的代码与仿制前创建的应用程序和库兼容 .

    来自Oracle Docs:

    类型Erasure Generics被引入到Java语言中,以便在编译时提供更严格的类型检查并支持通用编程 . 为了实现泛型,Java编译器将类型擦除应用于:如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或对象 . 因此,生成的字节码仅包含普通的类,接口和方法 . 如有必要,插入类型铸件以保持类型安全 . 生成桥接方法以保留扩展泛型类型中的多态性 . 类型擦除确保不为参数化类型创建新类;因此,泛型不会产生运行时开销 .

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

  • -3

    这是工作解决方案!

    @SuppressWarnings("unchecked")
        private Class<T> getGenericTypeClass() {
            try {
                String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
                Class<?> clazz = Class.forName(className);
                return (Class<T>) clazz;
            } catch (Exception e) {
                throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
            }
        }
    

    注意: Can be used only as superclass
    1.必须用类型类扩展( Child extends Generic<Integer>OR
    2.必须创建为匿名实现( new Generic<Integer>() {};

  • 14

    正如其他人所提到的那样,只有在某些情况下通过反思才有可能 .

    如果您确实需要该类型,这是通常的(类型安全的)解决方法模式:

    public class GenericClass<T> {
    
         private final Class<T> type;
    
         public GenericClass(Class<T> type) {
              this.type = type;
         }
    
         public Class<T> getMyType() {
             return this.type;
         }
    }
    
  • 265
    public static final Class<?> getGenericArgument(final Class<?> clazz)
    {
        return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
    }
    
  • 1

    它可能对某人有用 . 你可以使用java.lang.ref.WeakReference;这条路:

    class SomeClass<N>{
      WeakReference<N> variableToGetTypeFrom;
    
      N getType(){
        return variableToGetTypeFrom.get();
      }
    }
    
  • 36

    本_168156中描述的技术对我有用 .

    简而言之,简单快速的例子:

    public abstract class AbstractDAO<T extends EntityInterface, U extends QueryCriteria, V>
     {
        /**
         * Method returns class implementing EntityInterface which was used in class
         * extending AbstractDAO
         *
         * @return Class<T extends EntityInterface>
         */
        public Class<T> returnedClass()
        {
            return (Class<T>) getTypeArguments(AbstractDAO.class, getClass()).get(0);
        }
    
        /**
         * Get the underlying class for a type, or null if the type is a variable
         * type.
         *
         * @param type the type
         * @return the underlying class
         */
        public static Class<?> getClass(Type type)
        {
            if (type instanceof Class) {
                return (Class) type;
            } else if (type instanceof ParameterizedType) {
                return getClass(((ParameterizedType) type).getRawType());
            } else if (type instanceof GenericArrayType) {
                Type componentType = ((GenericArrayType) type).getGenericComponentType();
                Class<?> componentClass = getClass(componentType);
                if (componentClass != null) {
                    return Array.newInstance(componentClass, 0).getClass();
                } else {
                    return null;
                }
            } else {
                return null;
            }
        }
    
        /**
         * Get the actual type arguments a child class has used to extend a generic
         * base class.
         *
         * @param baseClass the base class
         * @param childClass the child class
         * @return a list of the raw classes for the actual type arguments.
         */
        public static <T> List<Class<?>> getTypeArguments(
                Class<T> baseClass, Class<? extends T> childClass)
        {
            Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
            Type type = childClass;
            // start walking up the inheritance hierarchy until we hit baseClass
            while (!getClass(type).equals(baseClass)) {
                if (type instanceof Class) {
                    // there is no useful information for us in raw types, so just keep going.
                    type = ((Class) type).getGenericSuperclass();
                } else {
                    ParameterizedType parameterizedType = (ParameterizedType) type;
                    Class<?> rawType = (Class) parameterizedType.getRawType();
    
                    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                    TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
                    for (int i = 0; i < actualTypeArguments.length; i++) {
                        resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
                    }
    
                    if (!rawType.equals(baseClass)) {
                        type = rawType.getGenericSuperclass();
                    }
                }
            }
    
            // finally, for each actual type argument provided to baseClass, determine (if possible)
            // the raw class for that type argument.
            Type[] actualTypeArguments;
            if (type instanceof Class) {
                actualTypeArguments = ((Class) type).getTypeParameters();
            } else {
                actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
            }
            List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
            // resolve types by chasing down type variables.
            for (Type baseType : actualTypeArguments) {
                while (resolvedTypes.containsKey(baseType)) {
                    baseType = resolvedTypes.get(baseType);
                }
                typeArgumentsAsClasses.add(getClass(baseType));
            }
            return typeArgumentsAsClasses;
        }
      }
    
  • 2

    使用 Guava .

    import com.google.common.reflect.TypeToken;
    import java.lang.reflect.Type;
    
    public abstract class GenericClass<T> {
      private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) { };
      private final Type type = typeToken.getType(); // or getRawType() to return Class<? super T>
    
      public Type getType() {
        return type;
      }
    
      public static void main(String[] args) {
        GenericClass<String> example = new GenericClass<String>() { };
        System.out.println(example.getType()); // => class java.lang.String
      }
    }
    

    前段时间,我发布了一些完整的例子,包括抽象类和子类here .

    注意:这要求您实例化 GenericClass 的子类,以便它可以正确绑定类型参数 . 否则它只会将类型返回为 T .

  • -4

    这是一种方式,我必须使用一次或两次:

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

    随着

    public class SpecificClass extends GenericClass<String>{
    
        @Override
        public Class<String> getMyType(){
            return String.class;
        }
    }
    
  • 2

    泛型在运行时不具体化 . 这意味着在运行时不存在信息 .

    在保留向后兼容性的同时向Java中添加泛型是一种游览力(你可以看到关于它的开创性论文:Making the future safe for the past: adding genericity to the Java programming language) .

    关于这个主题的文献很丰富,有些人对当前的状态有所了解,有些人说这实际上是一个lure并且没有真正需要它 . 你可以阅读两个链接,我发现它们很有趣 .

  • 6

    这是我的解决方案

    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;
        }
    }
    

    无论您的类层次结构具有多少级别,此解决方案仍然有效,例如:

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

    在这种情况下,getMyType()= java.lang.String

相关问题