60 votes

Comment faire pour déterminer la classe d'un type générique?

Je suis en création d'une classe générique et dans l'une des méthodes j'ai besoin de savoir la Classe de type générique, actuellement en cours d'utilisation. La raison en est que celui de la méthode que j'appel s'attend à ce qu'un argument.

Exemple:

public class MyGenericClass<T> {
  public void doSomething() {
    // Snip...
    // Call to a 3rd party lib
    T bean = (T)someObject.create(T.class);
    // Snip...
  }
}

Clairement l'exemple ci-dessus ne fonctionne pas et les résultats dans l'erreur suivante: Illégal de la classe littéral pour le paramètre de type T.

Ma question est: est-ce que quelqu'un connais une bonne alternative ou solution pour cela?

49voto

Nicolas Points 11558

Toujours les mêmes problèmes : les Génériques, les informations sont effacées lors de l'exécution, il ne peut pas être récupéré. Une solution de contournement est de passer à la classe T en paramètre d'une méthode statique :

public class MyGenericClass<T> {

    private final Class<T> clazz;

    public static <U> MyGenericClass<U> createMyGeneric(Class<U> clazz) {
        return new MyGenericClass<U>(clazz);
    }

    protected MyGenericClass(Class<T> clazz) {
        this.clazz = clazz;
    }

    public void doSomething() {
        T instance = clazz.newInstance();
    }
}

C'est moche, mais ça fonctionne.

22voto

Christoph Points 161

J'ai été tout a fait à cette solution:

import java.lang.reflect.ParameterizedType;

public abstract class A<B> {

        public Class<B> g() throws Exception {
                ParameterizedType superclass = (ParameterizedType)
        getClass().getGenericSuperclass();

                return (Class<B>) superclass.getActualTypeArguments()[0];
        }
}

4voto

Steven Collins Points 73

Malheureusement, Christoph solution comme l'écrit ne fonctionne que dans des circonstances très limitées. Notez que cela ne fonctionne que dans les classes abstraites, tout d'abord. L'autre difficulté, c'est qu' g() seulement des œuvres à partir des sous-classes DIRECTES de A. Nous pouvons résoudre ce problème, cependant:

private Class<?> extractClassFromType(Type t) throws ClassCastException {
    if (t instanceof Class<?>) {
        return (Class<?>)t;
    }
    return (Class<?>)((ParameterizedType)t).getRawType();
}

public Class<B> g() throws ClassCastException {
    Class<?> superClass = getClass(); // initial value
    Type superType;
    do {
        superType = superClass.getGenericSuperclass();
        superClass = extractClassFromType(superType);
    } while (! (superClass.equals(A.class)));

    Type actualArg = ((ParameterizedType)superType).getActualTypeArguments()[0];
    return (Class<B>)extractClassFromType(actualArg);
}

Ceci fonctionne dans beaucoup de situations dans la pratique, mais pas TOUT le temps. Considérer:

public class Foo<U,T extends Collection<?>> extends A<T> {}

(new Foo<String,List<Object>>() {}).g();

Cela permettra de jeter un ClassCastException, parce que le type de l'argument ici n'est pas un Class ou ParameterizedType ; c'est l' TypeVariable T. Alors maintenant, vous seriez coincé à essayer de comprendre à quel type T était censé reposer, et ainsi de suite vers le bas le trou de lapin.

Je pense que la seule raisonnable, de manière générale, la réponse est quelque chose qui s'apparente à Nicolas initiale de la réponse -- en général, si vos besoins de la classe à instancier des objets de la classe qui est inconnu au moment de la compilation, les utilisateurs de votre classe a besoin de passer que la classe littérale (ou, peut-être, une Usine) de votre classe explicitement et ne pas compter uniquement sur les médicaments génériques.

2voto

Jet Geng Points 299

j'ai trouver un autre moyen pour obtenir la Classe de l'objet générique

public Class<?> getGenericClass(){
         Class<?> result =null;
         Type type =this.getClass().getGenericSuperclass();

         if(type instanceofParameterizedType){
              ParameterizedType pt =(ParameterizedType) type;
              Type[] fieldArgTypes = pt.getActualTypeArguments();
              result =(Class<?>) fieldArgTypes[0];
        }
        return result;
  }

0voto

Jonathan Points 875

T peut être résolu assez facilement à l'aide de l'adresse typetools:

Class<T> t = (Class<T>) TypeResolver.resolveRawArguments(MyGenericClass.class, getClass());

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X