2016-04-02 5 views
3

J'essayais de trouver un moyen de créer une méthode interface/abstract avec la classe déclarative/d'extension en tant que type de retour. (par exemple, classA étend interfaceA, et la méthode devrait renvoyer un objet ClassA).Java - extension de la classe en tant que type de retour sur l'interface/méthode abstraite

Maintenant, j'ai trouvé un post que le compilateur ne se plaindrait pas de quelque chose comme ça, mais la JVM n'est pas capable de gérer une telle chose, ce qui signifie que ce mécanisme n'existe pas dans java.

Donc je suis venu avec l'idée suivante, à partir de laquelle je ne sais pas si c'est techniquement assez d'épargne pour faire. (par exemple va-t-il provoquer une boucle)

public interface ISomeInterface<T extends ISomeInterface<T>> { 
    public T get(); 
} 

ce qui signifie que vous pouvez l'utiliser de cette manière. Bien que cela ne marche pas forcer un utilisateur externe à utiliser la classe d'extension, au moins donne l'occasion de le faire si préféré:

public class ExtendingClass implements ISomeInterface<ExtendingClass>{ 
    @Override 
    public ExtendingClass get(){} 
} 

Maintenant, cela ne donne pas de compilateur ou erreur d'exécution, mais je suis inquiet si cela créerait des problèmes si elle est largement utilisée.

J'apprécierais que quelqu'un puisse confirmer que cela causerait ou ne causerait pas de problèmes. (Tout autre commentaire est le bienvenu).

+2

Je pense que cela fonctionne très bien. C'est le même modèle que Java utilise pour les types 'enum', qui sont déclarés comme [classe publique Enum >] (https://docs.oracle.com/javase/8/docs/api/java/lang /Enum.html) – markspace

+0

Comment cela ne vous donne-t-il pas une erreur de compilation? La classe d'implémentation n'est pas abstraite, vous avez donc besoin d'un corps de méthode pour cela. – Makoto

+0

@Makoto cela donnerait une erreur en effet: D, c'était juste un exemple. changé maintenant. – n247s

Répondre

2

Il n'y a rien de mal à cela. C'est en fait une pratique assez courante.

+0

Très bien, merci.J'espère vraiment qu'il y aura une meilleure solution pour cela bien qu'un jour. – n247s

1

C'est une pratique très courante. Les exemples incluent:

Enum<E extends Enum<E>> 

BaseStream<T, S extends BaseStream<T, S>> 

Cependant, assurez-vous de connaître les limitations. Le principal est que cela ne fonctionne pas bien avec l'héritage.

Par exemple, si vous disposez d'une interface

interface Animal<A extends Animal<A>> 

vous pouvez décider d'écrire une mise en œuvre concrète comme celui-ci

class Duck implements Animal<Duck> 

Cela fonctionne très bien, mais si vous vous décidez voulez étendre Duck , vous ne serez pas en mesure d'écrire ceci:

class MallardDuck extends Duck implements Animal<MallardDuck> 

La raison pour laquelle vous ne pouvez pas faites ceci est que vous ne pouvez pas implémenter la même interface générique avec deux paramètres de type différents - puisque Duck implémente déjà Animal<Duck>, il n'est pas possible pour MallardDuck d'implémenter Animal<MallardDuck>. Donc, assurez-vous que si vous utilisez ce modèle, vous réfléchissez très soigneusement à la façon dont vous allez implémenter l'interface. Cela fonctionne avec Enum parce que le langage ne vous permet pas de les étendre, mais s'il est trop utilisé, ce modèle peut créer un désordre total.

+0

Cela semble logique. bien que ce soit le cas avec des interfaces normales aussi bien? il cache essentiellement les genericTypes. Bien que j'obtienne ce que vous voulez dire, parce que la méthode a le type de retour 'Duck' (dans ce cas) une sous-classe ne peut plus changer ce type de retour. Bien que ce n'est pas différent d'une interface régulière. Quoi qu'il en soit merci de souligner. – n247s