173 votes

obtenir le type d'un paramètre générique en java avec réflexion

Est-il possible d'obtenir le type d'un paramètre générique?

Un exemple:

public final class Voodoo {
    public static void chill(List<?> aListWithTypeSpiderMan) { 
        // Here I'd like to get the Class-Object 'SpiderMan'
        Class typeOfTheList = ???;
    }

    public static void main(String... args) {
        chill(new ArrayList<SpiderMan>());
    }
}

177voto

DerMike Points 4280

Une construction, une fois, j'ai trébuché sur ressemblait

Class<T> persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];

Il semble donc y avoir une certaine réflexion-de la magie autour de ce que je unfortunetly ne comprends pas tout... Désolé.

160voto

Mark McKenna Points 915

Je veux essayer de briser la réponse de @DerMike pour expliquer:

Tout d'abord, le type d'effacement ne signifie pas que le JDK élimine les informations de type à l'exécution. C'est une méthode pour permettre le type de compilation vérification de l'exécution et la compatibilité du type de coexister dans la même langue. Que ce bloc de code l'indique, le JDK conserve la effacées les informations de type, c'est juste pas associés avec les fontes et les choses.

Deuxièmement, cette offre générique les informations de type d'une classe générique exactement à un niveau de la hiérarchie du type de béton en cours de vérification--c'est à dire un résumé parent de la classe avec des paramètres de type générique peut trouver les types de béton correspondant à son type de paramètres pour une mise en œuvre concrète de lui-même qu' directement en hérite. Si cette classe non abstraite et instancié, ou la mise en œuvre concrète sur deux niveaux, cela ne fonctionne pas (bien qu'un peu de crochetant pourrait le faire appliquer à tout nombre prédéterminé de niveaux au-delà de l'un, ou jusqu'à la plus basse classe avec X paramètres de type générique, et cetera).

De toute façon, à l'explication. Voici le code à nouveau séparés en lignes pour en faciliter la consultation:

Classe genericParameter0OfThisClass = 
(La classe)
((ParameterizedType)
getClass()
.getGenericSuperclass())
.getActualTypeArguments()[0];

Laissez-nous être de la classe abstraite avec les types génériques qui contient ce code. La lecture de ce à peu près à l'intérieur:

  • Ligne 4 obtient la classe de béton' instance de Classe. C'est l'identification immédiate de descendant du type de béton.
  • La ligne 5 de la catégorie supertype comme un Type; c'est nous. Puisque nous sommes une représentation paramétrique de type, on peut sans risque de fonte de nous-mêmes à ParameterizedType (ligne 3). La clé est que lorsque Java détermine ce Type d'objet, il utilise les informations de type présenter à l'enfant d'associer des informations de type avec nos paramètres de type dans la nouvelle ParameterizedType instance. Alors maintenant, nous pouvons accéder à des types concrets pour nos génériques.
  • Ligne 6 obtient le tableau de types mappés dans notre génériques, dans l'ordre tel que déclaré dans le code de la classe. Pour cet exemple, nous tirez le premier paramètre. Cela revient comme un Type.
  • Ligne 2 fait le dernier Type est retourné à une Classe. C'est sûr, parce que nous savons quels types de nos paramètres de type générique sont en mesure de prendre et peut confirmer qu'ils vont tous être des classes (je ne suis pas sûr de savoir comment en Java on pourrait aller d'obtenir un paramètre générique qui ne dispose pas d'une instance de la Classe associée avec elle, en fait).

...et c'est assez bien. Donc nous appuyer sur des informations de type à partir de notre propre mise en œuvre concrète de retour sur soi-même, et l'utiliser pour accéder à une classe de la poignée. nous pourrions doubler getGenericSuperclass() et passez deux niveaux, ou d'éliminer getGenericSuperclass() et obtenir les valeurs pour nous-mêmes comme un type de béton (avertissement: je n'ai pas testé ces scénarios, ils ne sont pas venus pour moi encore).

Ce qui est difficile si votre béton enfants sont être un nombre arbitraire de sauts, ou si vous êtes en béton et pas définitif, et particulièrement difficile si vous vous attendez à un de vos (variable de profondeur) les enfants d'avoir leur propre génériques. Mais vous pouvez généralement la conception sur la base de ces considérations, c'est vous.

Espérons que cela a aidé à quelqu'un! Je reconnais que ce post est ancien. Je vais probablement snip cette explication et de les conserver pour d'autres questions.

23voto

Andrey Rodionov Points 360

En fait j'ai obtenu ce travail. Considérons le fragment de code suivant:

Method m;
Type[] genericParameterTypes = m.getGenericParameterTypes();
for (int i = 0; i < genericParameterTypes.length; i++) {
     if( genericParameterTypes[i] instanceof ParameterizedType ) {
                Type[] parameters = ((ParameterizedType)genericParameterTypes[i]).getActualTypeArguments();
//parameters[0] contains java.lang.String for method like "method(List<String> value)"

     }
 }

Je suis l'aide de jdk 1.6

22voto

Je me suis réveiller ce fil :-) Il y a une solution en fait, par l'application de la "classe anonyme" truc et les idées de la Super Jetons de Type:

public final class Voodoo {
    public static void chill(final List<?> aListWithSomeType) {
        // Here I'd like to get the Class-Object 'SpiderMan'
        System.out.println(aListWithSomeType.getClass().getGenericSuperclass());
        System.out.println(((ParameterizedType) aListWithSomeType
            .getClass()
            .getGenericSuperclass()).getActualTypeArguments()[0]);
    }
    public static void main(String... args) {
        chill(new ArrayList<SpiderMan>() {});
    }
}
class SpiderMan {
}

L'astuce réside dans la création d'une classe anonyme new ArrayList<SpiderMan>() {} à la place de l'original (simple) new ArrayList<SpiderMan>(). L'utilisation d'un anoymous classe (si possible) veille à ce que le compilateur conserve des informations sur le type de l'argument SpiderMan étant donné le type de paramètre List<?>. Voilà !

7voto

Michael Borgwardt Points 181658

Non, c'est pas possible. En raison de la baisse des problèmes de compatibilité, de Java génériques sont basés sur le type d'effacement, j'.un. au moment de l'exécution, tout ce que vous avez est un non-générique List objet. Il y a quelques informations sur les paramètres de type à l'exécution, mais il réside dans les définitions de classe (c'est à dire que vous pouvez demander "quel type générique t ce domaine de la définition de l'utiliser?"), pas dans les instances d'objet.

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