Je sais qu'il n'est pas possible de définir un constructeur dans une interface. Mais je me demande pourquoi, car je pense que cela pourrait être très utile.
Vous pouvez donc être sûr que certains champs d'une classe sont définis pour chaque implémentation de cette interface.
Par exemple, considérez la classe de message suivante:
public class MyMessage {
public MyMessage(String receiver) {
this.receiver = receiver;
}
private String receiver;
public void send() {
//some implementation for sending the mssage to the receiver
}
}
Si vous définissez une interface pour cette classe afin que je puisse avoir plus de classes qui implémentent l'interface de message, je ne peux définir que la méthode d'envoi et non le constructeur. Alors, comment puis-je m'assurer que chaque implémentation de cette classe a vraiment un ensemble de récepteurs? Si j'utilise une méthode comme celle-ci, setReceiver(String receiver)
je ne peux pas être sûr que cette méthode est vraiment appelée. Dans le constructeur, je pourrais le garantir.
Réponses:
Prenant certaines des choses que vous avez décrites:
... ces exigences sont exactement à quoi servent les classes abstraites .
la source
Message
interface qui définit lasend()
méthode, et si Sebi souhaite fournir une classe "de base" pour les implémentations de l'Message
interface, alors fournissez uneAbstractMessage
aussi. Les classes abstraites ne devraient pas remplacer les interfaces, n'a jamais tenté de le suggérer.Un problème que vous rencontrez lorsque vous autorisez les constructeurs dans les interfaces vient de la possibilité d'implémenter plusieurs interfaces en même temps. Lorsqu'une classe implémente plusieurs interfaces qui définissent différents constructeurs, la classe devrait implémenter plusieurs constructeurs, chacun satisfaisant une seule interface, mais pas les autres. Il sera impossible de construire un objet qui appelle chacun de ces constructeurs.
Ou en code:
la source
class A implements Named, HashList { A(){HashList(new list()); Named("name");} }
new Set<Fnord>()
pouvait être interprétée comme signifiant "Donnez-moi quelque chose que je peux utiliser commeSet<Fnord>
"; si l'auteur deSet<T>
avait l'intentionHashSet<T>
d'être l'implémentation de référence pour des choses qui n'avaient pas besoin de quelque chose d'autre, l'interface pourrait alors définirnew Set<Fnord>()
pourrait être considérée comme synonyme denew HashSet<Fnord>()
. Pour une classe, implémenter plusieurs interfaces ne poserait aucun problème, car ilnew InterfaceName()
faudrait simplement construire une classe désignée par l'interface .A(String,List)
constructeur pourrait être le constructeur désigné,A(String)
etA(List)
pourrait être des constructeurs secondaires qui l'appellent. Votre code n'est pas un contre-exemple, juste un mauvais.Une interface définit un contrat pour une API, c'est-à-dire un ensemble de méthodes sur lesquelles le réalisateur et l'utilisateur de l'API s'accordent. Une interface n'a pas d'implémentation instanciée, donc pas de constructeur.
Le cas d'utilisation que vous décrivez s'apparente à une classe abstraite dans laquelle le constructeur appelle une méthode d'une méthode abstraite qui est implémentée dans une classe enfant.
Le problème inhérent ici est que pendant que le constructeur de base est en cours d'exécution, l'objet enfant n'est pas encore construit, et donc dans un état imprévisible.
Pour résumer: cela pose-t-il des problèmes lorsque vous appelez des méthodes surchargées à partir de constructeurs parents, pour citer mindprod :
la source
Une solution que vous pouvez essayer consiste à définir un
getInstance()
méthode dans votre interface afin que l'implémenteur sache quels paramètres doivent être gérés. Ce n'est pas aussi solide qu'une classe abstraite, mais cela permet plus de flexibilité en tant qu'interface.Toutefois, cette solution de contournement nécessite que vous
getInstance()
utilisiez pour instancier tous les objets de cette interface.Par exemple
la source
Il n'y a que des champs statiques dans l'interface qui n'ont pas besoin d'être initialisés lors de la création d'objet dans la sous-classe et la méthode d'interface doit fournir une implémentation réelle dans la sous-classe. Il n'y a donc pas besoin de constructeur dans l'interface.
Deuxième raison - lors de la création de l'objet de la sous-classe, le constructeur parent est appelé .Mais s'il y a plus d'une interface implémentée, un conflit se produira lors de l'appel du constructeur d'interface quant à savoir quel constructeur d'interface appellera en premier
la source
Si vous voulez vous assurer que chaque implémentation de l'interface contient un champ spécifique, il vous suffit d'ajouter à votre interface le getter pour ce champ :
Receiver
objet doit être passé à la classe d'une manière ou d'une autre (soit par constructeur, soit par setter)la source
Les dépendances qui ne sont pas référencées dans une méthode d'interface doivent être considérées comme des détails d'implémentation, et non comme quelque chose que l'interface applique. Bien sûr, il peut y avoir des exceptions, mais en règle générale, vous devez définir votre interface comme le comportement attendu. L'état interne d'une implémentation donnée ne devrait pas être une préoccupation de conception de l'interface.
la source
Voir cette question pour le pourquoi (tiré des commentaires).
Si vous avez vraiment besoin de faire quelque chose comme ça, vous voudrez peut-être une classe de base abstraite plutôt qu'une interface.
la source
Ceci est dû au fait que les interfaces ne permettent pas de définir le corps de la méthode, mais nous devrions avoir à définir le constructeur dans la même classe que les interfaces ont par défaut un modificateur abstrait pour toutes les méthodes à définir. C'est pourquoi nous ne pouvons pas définir de constructeur dans les interfaces.
la source
Voici un exemple utilisant cette technique. Dans cet exemple spécifique, le code fait un appel à Firebase en utilisant une maquette
MyCompletionListener
qui est une interface masquée comme une classe abstraite, une interface avec un constructeurla source
private
modificateur d'accès avecinterface
?Généralement, les constructeurs servent à initialiser les membres non statiques d'une classe particulière par rapport à un objet.
Il n'y a pas de création d'objet pour l'interface car il n'y a que des méthodes déclarées mais pas des méthodes définies. Pourquoi nous ne pouvons pas créer d'objet pour les méthodes déclarées La création est-objet n'est rien d'autre que l'allocation de mémoire (dans la mémoire du tas) pour les membres non statiques.
JVM créera de la mémoire pour les membres qui sont entièrement développés et prêts à l'emploi. Sur la base de ces membres, JVM calcule la quantité de mémoire nécessaire pour eux et crée de la mémoire.
En cas de méthodes déclarées, JVM est incapable de calculer la quantité de mémoire requise pour ces méthodes déclarées car l'implémentation se fera à l'avenir, ce qui n'est pas fait à ce moment-là. donc la création d'objet n'est pas possible pour l'interface.
conclusion:
sans création d'objet, il n'y a aucune chance d'initialiser les membres non statiques via un constructeur, c'est pourquoi le constructeur n'est pas autorisé à l'intérieur d'une interface (car il n'y a pas d'utilisation de constructeur dans une interface)
la source