Objet générique Java avec plusieurs interfaces de casting

Supposons que j’utilise une classe générique déclarée comme ceci:

public class ConfigurableRuleKey extends Key { private final R rule public ConfigurableRuleKey(R rule) { this.rule = rule; } /* Additional methods are declared here */ } 

Et je veux implémenter une méthode d’usine qui vérifie si la règle passée implémente l’interface Configurable , lorsque vous créez une règle configurable ou créez simplement une clé de base:

 public static  Key create(R rule) { if (rule instanceof Configurable) { return new ConfigurableRuleKey(rule); //This will not compile } else { return new RuleKey(rule); } } 

Le problème est que, dans ma méthode d’usine, je ne peux pas transmettre la règle au constructeur de ConfigurableRuleKey car elle ne correspond pas aux contraintes génériques déclarées (événement si j’avais explicitement vérifié qu’il implémentait Configurable ). La question est de savoir comment puis-je transtyper mon instance de règle afin qu’elle s’adapte aux ressortingctions du constructeur dans ConfigurableRuleKey ?

J’ai trouvé un moyen de faire ce que vous demandez sans utiliser de types bruts, mais cela implique tout de même une série d’incantations non contrôlées:

 @SuppressWarnings("unchecked") public static  Key create(R rule) { if (rule instanceof Configurable) { return (Key)new ConfigurableRuleKey<>((T)rule); } else { return new RuleKey<>(rule); } } 

Je ne suis pas sûr que ce soit mieux que la réponse de sp00m, mais c’est au moins différent. 🙂

La raison insortingnsèque pour laquelle cela ne peut pas être construit correctement dans les génériques de Java semble être que les types d’intersection doivent être construits à partir d’interfaces concrètes et ne peuvent pas être construits à partir d’autres variables de type. Par conséquent, il n’y a aucun moyen de construire T dans cet exemple de telle sorte qu’il soit limité par R Sans cette fonctionnalité, il n’existe même pas de moyen d’avoir une méthode magique semblable à Class.asSubclass pour Class.asSubclass ce comportement.

EDIT: De même, il semble que Java 8 ait introduit des types d’intersections anonymes dans lesquels vous pouvez transtyper vers plusieurs interfaces – par exemple. (Configurable & Rule)rule – mais même cela n’aide en rien puisque, pour la même raison que celle décrite ci-dessus, vous ne pouvez pas utiliser la conversion en (Configurable & R) . Cela aiderait à se débarrasser de la variable de type T , cependant:

 @SuppressWarnings("unchecked") public static  Key create(R rule) { if (rule instanceof Configurable) { return (Key)new ConfigurableRuleKey<>((Configurable & Rule)rule); } else { return new RuleKey<>(rule); } } 

Cela devrait convenir à vos besoins:

 @SuppressWarnings({ "rawtypes", "unchecked" }) public static  Key create(R rule) { if (rule instanceof Configurable) { return new ConfigurableRuleKey((Configurable) rule); } else { return new RuleKey<>(rule); } } 

Vous avez vérifié manuellement que la rule est Configurable , de sorte que la conversion est sécurisée.