Java 在运行时获取类的泛型类型

Java 在运行时获取类的泛型类型,java,generics,reflection,Java,Generics,Reflection,我怎样才能做到这一点 public class GenericClass<T> { public Type getMyType() { //How do I return the type of T? } } 公共类GenericClass { 公共类型getMyType() { //如何返回T的类型? } } 到目前为止,我尝试过的所有方法都会返回类型Object,而不是使用的特定类型。我不认为您可以,Java在编译时使用类型擦除,因此您

我怎样才能做到这一点

public class GenericClass<T>
{
    public Type getMyType()
    {
        //How do I return the type of T?
    }
}
公共类GenericClass
{
公共类型getMyType()
{
//如何返回T的类型?
}
}

到目前为止,我尝试过的所有方法都会返回类型
Object
,而不是使用的特定类型。

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

从Oracle文档:

类型擦除

Java语言中引入了泛型以提供更紧密的类型 在编译时进行检查,以支持泛型编程。到 实现泛型,Java编译器将类型擦除应用于:

将泛型类型中的所有类型参数替换为其边界或 对象,如果类型参数是无界的。产生的字节码, 因此,只包含普通类、接口和方法。 如有必要,插入类型强制转换以保持类型安全。生成 在扩展泛型类型中保留多态性的桥接方法。 类型擦除可确保不会为参数化类型创建新类 类型;因此,泛型不会产生运行时开销


我认为您不能,Java在编译时使用类型擦除,因此您的代码与泛型之前创建的应用程序和库兼容

从Oracle文档:

类型擦除

Java语言中引入了泛型以提供更紧密的类型 在编译时进行检查,以支持泛型编程。到 实现泛型,Java编译器将类型擦除应用于:

将泛型类型中的所有类型参数替换为其边界或 对象,如果类型参数是无界的。产生的字节码, 因此,只包含普通类、接口和方法。 如有必要,插入类型强制转换以保持类型安全。生成 在扩展泛型类型中保留多态性的桥接方法。 类型擦除可确保不会为参数化类型创建新类 类型;因此,泛型不会产生运行时开销


你不能。如果向类中添加类型为T的成员变量(甚至不必对其进行初始化),则可以使用该变量来恢复该类型。

您不能。如果将类型为T的成员变量添加到类中(甚至不必对其进行初始化),则可以使用该变量来恢复该类型。

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

在保持向后兼容性的同时向Java中添加泛型是一项非常艰巨的任务(您可以看到关于它的开创性论文:)

关于这个问题有很多文献,有些人对目前的状况持赞同态度,有些人说这实际上是一个问题,没有真正的必要。您可以阅读这两个链接,我发现它们非常有趣。

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

在保持向后兼容性的同时向Java中添加泛型是一项非常艰巨的任务(您可以看到关于它的开创性论文:)


关于这个问题有很多文献,有些人对目前的状况持赞同态度,有些人说这实际上是一个问题,没有真正的必要。您可以阅读这两个链接,我发现它们非常有趣。

我看到过类似的内容

private Class<T> persistentClass;

public Constructor() {
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                            .getGenericSuperclass()).getActualTypeArguments()[0];
 }
私有类persistentClass;
公共构造函数(){
this.persistentClass=(Class)((ParameteredType)getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}

在这个例子中,我看到了类似的情况

private Class<T> persistentClass;

public Constructor() {
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                            .getGenericSuperclass()).getActualTypeArguments()[0];
 }
私有类persistentClass;
公共构造函数(){
this.persistentClass=(Class)((ParameteredType)getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}

在这个例子中

正如其他人所提到的,只有在某些情况下通过反射才能实现

如果您确实需要该类型,这是常见的(类型安全)变通模式:

public class GenericClass<T> {

     private final Class<T> type;

     public GenericClass(Class<T> type) {
          this.type = type;
     }

     public Class<T> getMyType() {
         return this.type;
     }
}
公共类GenericClass{
私有最终类类型;
公共泛型类(类类型){
this.type=type;
}
公共类getMyType(){
返回此.type;
}
}

正如其他人提到的,只有在某些情况下通过反射才能实现

如果您确实需要该类型,这是常见的(类型安全)变通模式:

public class GenericClass<T> {

     private final Class<T> type;

     public GenericClass(Class<T> type) {
          this.type = type;
     }

     public Class<T> getMyType() {
         return this.type;
     }
}
公共类GenericClass{
私有最终类类型;
公共泛型类(类类型){
this.type=type;
}
公共类getMyType(){
返回此.type;
}
}

Java泛型大多是编译时的,这意味着类型信息在运行时丢失

class GenericCls<T>
{
    T t;
}
要在运行时获取类型信息,必须将其添加为ctor的参数

class GenericCls<T>
{
     private Class<T> type;
     public GenericCls(Class<T> cls)
     {
        type= cls;
     }
     Class<T> getType(){return type;}
}
类GenericCls
{
私人阶级类型;
公共通用cls(类别cls)
{
类型=cls;
}
类getType(){return type;}
}
例如:

GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;
GenericCls实例=新的GenericCls(String.class);
assert instance.getType()==String.class;

Java泛型大多是编译时的,这意味着类型信息在运行时丢失

class GenericCls<T>
{
    T t;
}
要在运行时获取类型信息,必须将其添加为ctor的参数

class GenericCls<T>
{
     private Class<T> type;
     public GenericCls(Class<T> cls)
     {
        type= cls;
     }
     Class<T> getType(){return type;}
}
类GenericCls
{
私人阶级类型;
公共通用cls(类别cls)
{
类型=cls;
}
类getType(){return type;}
}
例如:

GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;
GenericCls实例=新的GenericCls(String.class);
assert instance.getType()==String.class;
当然可以

出于向后兼容性的原因,Java在运行时不使用这些信息。但是信息实际上是以元数据的形式存在的,并且可以通过反射进行访问(但它仍然没有用于类型检查)

从官方API:

但是,对于您的场景,我不会使用反射。我
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
  }
}
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();
    }

}
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();
    // ...
}
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();
    }
}
@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 <> ");
        }
    } 
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());
    }
}
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();
}
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> {

}
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);
    }
}
public abstract class AbstractDao<T>
{
    private final Class<T> persistentClass;

    public AbstractDao()
    {
        this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
                .getActualTypeArguments()[0];
    }
}
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());
    }
}
public static final Class<?> getGenericArgument(final Class<?> clazz)
{
    return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
}
class SomeClass<N>{
  WeakReference<N> variableToGetTypeFrom;

  N getType(){
    return variableToGetTypeFrom.get();
  }
}
class A<T : SomeClass>() {

    var someClassType : T

    init(){
    this.someClassType = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>
    }

}
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;

public class TypeUtils {

    /*** EXAMPLES ***/

    public static class Class1<A, B, C> {

        public A someA;
        public B someB;
        public C someC;

        public Class<?> getAType() {
            return getTypeParameterType(this.getClass(), Class1.class, 0);
        }

        public Class<?> getCType() {
            return getTypeParameterType(this.getClass(), Class1.class, 2);
        }
    }

    public static class Class2<D, A, B, E, C> extends Class1<A, B, C> {

        public B someB;
        public D someD;
        public E someE;
    }

    public static class Class3<E, C> extends Class2<String, Integer, Double, E, C> {

        public E someE;
    }

    public static class Class4 extends Class3<Boolean, Long> {

    }

    public static void test() throws NoSuchFieldException {

        Class4 class4 = new Class4();
        Class<?> typeA = class4.getAType(); // typeA = Integer
        Class<?> typeC = class4.getCType(); // typeC = Long

        Field fieldSomeA = class4.getClass().getField("someA");
        Class<?> typeSomeA = TypeUtils.getFieldType(class4.getClass(), fieldSomeA); // typeSomeA = Integer

        Field fieldSomeE = class4.getClass().getField("someE");
        Class<?> typeSomeE = TypeUtils.getFieldType(class4.getClass(), fieldSomeE); // typeSomeE = Boolean


    }

    /*** UTILS ***/

    public static Class<?> getTypeVariableType(Class<?> subClass, TypeVariable<?> typeVariable) {
        Map<TypeVariable<?>, Type> subMap = new HashMap<>();
        Class<?> superClass;
        while ((superClass = subClass.getSuperclass()) != null) {

            Map<TypeVariable<?>, Type> superMap = new HashMap<>();
            Type superGeneric = subClass.getGenericSuperclass();
            if (superGeneric instanceof ParameterizedType) {

                TypeVariable<?>[] typeParams = superClass.getTypeParameters();
                Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments();

                for (int i = 0; i < typeParams.length; i++) {
                    Type actualType = actualTypeArgs[i];
                    if (actualType instanceof TypeVariable) {
                        actualType = subMap.get(actualType);
                    }
                    if (typeVariable == typeParams[i]) return (Class<?>) actualType;
                    superMap.put(typeParams[i], actualType);
                }
            }
            subClass = superClass;
            subMap = superMap;
        }
        return null;
    }

    public static Class<?> getTypeParameterType(Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
        return TypeUtils.getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex]);
    }

    public static Class<?> getFieldType(Class<?> clazz, AccessibleObject element) {
        Class<?> type = null;
        Type genericType = null;

        if (element instanceof Field) {
            type = ((Field) element).getType();
            genericType = ((Field) element).getGenericType();
        } else if (element instanceof Method) {
            type = ((Method) element).getReturnType();
            genericType = ((Method) element).getGenericReturnType();
        }

        if (genericType instanceof TypeVariable) {
            Class<?> typeVariableType = TypeUtils.getTypeVariableType(clazz, (TypeVariable) genericType);
            if (typeVariableType != null) {
                type = typeVariableType;
            }
        }

        return type;
    }

}
public class GenericClass<T> {
    private T data;
}
System.out.println(data.getClass().getSimpleName()); // "String", "Integer", etc.
public interface IGenericType<T>
{
    Class<T> getGenericTypeParameterType();
}
//Passed into the generic value generator function: toStore
//This value name is a field in the enclosing class.
//IUnionTypeValue<T> is a generic interface that extends IGenericType<T>
value = new IUnionTypeValue<T>() {
    ...
    private T storedValue = toStore;
    ...
    
    @SuppressWarnings("unchecked")
    @Override
    public Class<T> getGenericTypeParameterType()
    {
        return (Class<T>) storedValue.getClass();
    }
}