puis-je instancier de manière réfléchie un type générique dans Java?
Est-il possible de reflectively instancier un type générique en Java? À l'aide de la technique décrite ici j'obtiens une erreur parce que la classe jetons ne peuvent pas être générique. Prenons l'exemple ci-dessous. Je veux instancier certains sous-classe de Créateur qui implémente Créateur. Le nom de la classe réelle est passé en argument de ligne de commande. L'idée est d'être capable de spécifier une mise en œuvre du Créateur au moment de l'exécution. Est-il une autre façon d'accomplir ce que je suis en train de faire ici?
public interface Creator<T> {
T create();
}
public class StringCreator implements Creator<String> {
public String create() { return new String(); }
}
public class FancyStringCreator implements Creator<String> {
public String create() { return new StringBuffer().toString(); }
}
public static void main(String[] args) throws Exception {
Class<?> someClass = Class.forName(args[0]);
/*ERROR*/Class<? extends Creator<String>> creatorClass = someClass.asSubclass(Creator.class);
Constructor<? extends Creator<String>> creatorCtor = creatorClass.getConstructor((Class<?>[]) null);
Creator<String> creator = creatorCtor.newInstance((Object[]) null);
}
Edit: j'aime Marcus' approche la plus simple et pragmatique, et ce sans contourner l'ensemble des génériques chose. Je peux l'utiliser dans ma situation parce que je peux préciser que la classe a réussi doit être une sous-classe de StringCreator. Mais comme Ericsson, a souligné le générique de l'information est encore là, au niveau du type, tout simplement pas au niveau d'exécution de sorte qu'il est encore possible de reflectively examiner si une classe implémente le bon type générique.
source d'informationauteur sk.
Vous devez vous connecter pour publier un commentaire.
Le générique de l'information est perdue dans l'exécution. Il n'y a pas d'exécution équivalent d'un Créateur<String>.classe. Vous pouvez créer un type entre le Créateur et la StringCreator qui fixe le type générique:
Mais bien sûr, vous perdez un peu de souplesse, parce que vous ne pouvez pas utiliser les éléments suivants créateur de la classe:
Cela va faire ce que vous essayez de faire tout en fournissant le type de sécurité. Il n'y a aucun moyen d'éviter une décoché l'avertissement, mais le type de vérification fait ici justifie sa suppression.
La principale restriction que vous avez à respecter est qu'une classe dans la hiérarchie devez spécifier le paramètre de type. Par exemple
class MyCreator implements Creator<String>
. Vous ne pouvez pas l'utiliser avecclass GenericCreator<T> implements Creator<T>
.Il ne dispose pas actuellement de traiter le cas valide lorsque vous créez une nouvelle interface
interface StringCreatorIfc extends Creator<String>
et ont une classe à mettre en œuvre. Il pourrait être amélioré pour le faire, mais je vais laisser ça comme un exercice pour ceux qui sont enclins.Vous n'avez pas besoin de cette ligne. Ni avez-vous besoin le constructeur que vous êtes tout simplement à l'aide de la valeur par défaut. Il vous suffit d'instancier la classe:
Si vous insistez, vous ne serez en mesure d'obtenir à mi-chemin:
Pas très bien pourquoi vous êtes à l'utilisation de génériques ici.
L'instanciation de l'objet à l'aide de la réflexion suggère un usage général, mais sans doute vous allez appeler
create
à un certain point, et affecter le résultat à uneString
sinon pourquoi utiliser les génériques de contrôler le type de retour.Mais si vous avez écrit la suite de la mise en œuvre du Créateur:
Et l'a adopté en tant qu'argument, vous obtiendrez une ClassCastException lors de l'appel de
create
et l'affectation du résultat.