12
votes

Création d'un objet de type paramétré à l'aide de la classe anonyme

Ceci pourrait être une question stupide, mais je viens de voir une question demandant Comment créer une variable de type pour un type générique . Le consensus semblait être que vous devriez avoir une méthode factice qui renvoie ce type, puis utilisez la réflexion pour l'obtenir (dans ce cas, il souhaitait mappe code>). Quelque chose comme ça:

Type mapStringString = new ParameterizedType() {
    public Type getRawType() {
        return Map.class;
    }

    public Type getOwnerType() {
        return null;
    }

    public Type[] getActualTypeArguments() {
        return new Type[] { String.class, String.class };
    }
};


1 commentaires

J'essaie de faire ce que votre solution proposée permet: Obtenez un type paramétré à partir d'un type brut et de la liste des paramètres de type fournis à l'heure de la compilation. Avez-vous trouvé une autre façon de faire cela?


4 Réponses :


8
votes

Bien sûr, et pour la plupart des applications, cela serait probablement suffisant.

Cependant, en utilisant la première méthode, vous obtenez un objet plus raffiné. Disons par exemple que vous créez un objet type1 à l'aide de la première méthode et type2 à l'aide de la deuxième méthode. Alors type1.equals (type2) retournerait true (puisque la première méthode renvoie un objet qui implémente correctement la méthode EQUALS) mais type2.equals (type1) retournerait faux (Depuis dans la deuxième méthode, vous n'avez pas remplacé la méthode des égaux et utilisez la mise en œuvre à partir de objet ).

Même raisonnement s'applique à d'autres (méthodes parfois utiles) telles que Tostring , hashcode etc. La deuxième méthode ne fournit pas de mise en œuvre utile de ceux-ci.


2 commentaires

En fait, Type1 (Sun.Reflect.Generics.ReflectiveObjectS.ParameDeDtypeMPEIMP L) La mise en œuvre d'équivalements semble lancer le paramètre d'équivalent à des éléments paramétionnés, puis utilisez les méthodes d'interface pour comparer les classes, donc type1.equals (type2) retournerait vrai, bien que l'inverse ( type2.equals (type1) ) reviendrait faux; Vous pouvez également mettre en œuvre ceux-ci aussi, mais le code devient alors un peu chunky


Sûr. Vous pouvez obtenir le même résultat dans la méthode 2 comme dans la méthode 1, mais cela nécessite d'autres travaux, comme vous l'avez remarqué.



2
votes

En fait, je pense que le moyen le plus simple (== moins de code) est une interface factice qui étend le type de votre intéressé, puis GetGenericinterfaces () [0] code> de sa classe (Utiliser GetGenericClass () si vous êtes intéressé par une classe):

private interface MapStringString extends Map<String, String> {}
private static ParameterizedType mapStringString(){
    return (ParameterizedType) MapStringString.class.getGenericInterfaces()[0];
}


1 commentaires

Bien que cela semble "hacjou" comme la première méthode que j'ai donnée, cela donne au moins un meilleur code de recherche où vous essayez d'obtenir le type (appeler simplement la fonction au lieu de faire la classe, puis obtenir une méthode de retour générique à chaque fois vous voulez l'utiliser).



7
votes

Si vous incluez Google bibliothèque GUAVA dans votre projet (vous devriez; c'est génial ), utilisez son < Code> Typeoken pour obtenir un type. bibliothèque GSON (pour interagir avec JSON) a un version . Les deux sont utilisés comme celui-ci (pour obtenir un type type représentant Liste : xxx

si vous ne voulez pas compter sur Toutes les bibliothèques tierces, vous pouvez toujours utiliser des types anonymes pour obtenir un type générique concret avec une ligne de code (cette technique ne fonctionnera pas avec des interfaces et pourrait être plus de problèmes que cela ne vaut pour les types abstraits) . Pour obtenir un type type représentant hashmap , faites ceci: xxx

J'ai vérifié que résultant Type Instance .Qquals () Type Les instances créées par GSON 'S typé (code> , mais n'a pas vérifié la même chose pour la version de GUAVA de Typeoken , que je n'ai pas accès à pour le moment. (Guava est une bibliothèque plus générale qui est si pratique pour toutes sortes de choses, vous devriez probablement l'utiliser de toute façon.)


1 commentaires

Cela nécessite toujours que la liste est connue à l'heure de la compilation. Dans l'OP, les types de type brut et de paramètre n'étaient pas connus avant le type de compilation.



1
votes

En plus des libs mentionnés de Google, il existe également une lib de Apache qui fait le travail.

import org.apache.commons.lang3.reflect.TypeUtils;
...
ParameterizedType type = TypeUtils.parameterize(List.class, Double.class);
...


0 commentaires