Получить универсальный тип класса во время выполнения - PullRequest
442 голосов
/ 04 августа 2010

Как мне этого добиться?

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

Все, что я пробовал до сих пор, всегда возвращает тип Object, а не конкретный используемый тип.

Ответы [ 23 ]

8 голосов
/ 14 июля 2016

Я думаю, что есть другое элегантное решение.

То, что вы хотите сделать, - это (безопасно) "передать" тип параметра универсального типа из конкретного класса в суперкласс.

Если вы позволите себе думать о типе класса как о «метаданных» в классе, это предполагает использование метода Java для кодирования метаданных во время выполнения: annotations.

Сначала определите пользовательскую аннотацию в следующих строках:*

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

Некоторые ограничения этого подхода:

  1. Вы указываете универсальный тип (PassedGenericType) в ДВУХ местах, а не в том, который не является СУХИМЫМ.возможно, если вы можете изменить конкретные подклассы.
8 голосов
/ 01 января 2013

Это мое решение:

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);
      }
    }
  }
}
6 голосов
/ 30 ноября 2015

Вот рабочий раствор !!!

@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 <> ");
        }
    } 

ПРИМЕЧАНИЯ: Может использоваться только как суперкласс
1. Должен быть расширен типизированным классом (Child extends Generic<Integer>)
OR

2. Должен быть создан как анонимная реализация (new Generic<Integer>() {};)

3 голосов
/ 04 августа 2010

Вы не можете. Если вы добавите в класс переменную-член типа T (вам даже не нужно ее инициализировать), вы можете использовать ее для восстановления типа.

3 голосов
/ 17 мая 2016

Чтобы завершить некоторые ответы здесь, мне нужно было получить ParametrizedType 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());
    }
}
3 голосов
/ 08 марта 2018

Одно простое решение для этой кабины, как показано ниже

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 голосов
/ 14 марта 2013

Вот один способ, который мне пришлось использовать один или два раза:

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

Наряду с

public class SpecificClass extends GenericClass<String>{

    @Override
    public Class<String> getMyType(){
        return String.class;
    }
}
1 голос
/ 27 июля 2016

Вот мое решение

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

1 голос
/ 15 августа 2014

На всякий случай, если вы используете переменную store с использованием универсального типа, вы легко можете решить эту проблему, добавив метод 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();
    // ...
}
1 голос
/ 05 марта 2014

Вот мой трюк:

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

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...