J'apprends juste Java et je ne suis pas un programmeur pratiquant.
Le livre que je suis en train de dire dit que lors du remplacement d'une méthode, les types d'arguments doivent être les mêmes, mais les types de retour peuvent être polymorphiquement compatibles.
Ma question est pourquoi les arguments passés à la méthode prioritaire ne peuvent-ils pas être un type de sous-classe du super-type attendu?
Dans la méthode surchargée, la méthode que j'appelle sur l'objet est garantie d'être définie sur l'objet.
Remarques sur les doublons suggérés:
La première suggestion semble concerner la hiérarchie des classes et l'emplacement des fonctionnalités. Ma question est plus axée sur la raison pour laquelle la restriction linguistique existe.
La deuxième suggestion explique comment faire ce que je demande, mais pas pourquoi cela doit être fait de cette façon. Ma question porte sur le pourquoi.
la source
Réponses:
Le concept auquel vous faites initialement référence dans votre question est appelé type de retour covariant .
Les types de retour covariants fonctionnent car une méthode est censée renvoyer un objet d'un certain type et les méthodes de substitution peuvent en renvoyer une sous-classe. Sur la base des règles de sous-typage d'un langage comme Java, s'il
S
s'agit d'un sous-type deT
, alors partout oùT
apparaît, nous pouvons passer unS
.En tant que tel, il est sûr de retourner un
S
lors de la substitution d'une méthode qui attendait aT
.Votre suggestion d'accepter qu'une substitution d'une méthode utilise des arguments qui sont des sous-types de ceux demandés par la méthode substituée est beaucoup plus compliquée car elle conduit à des anomalies dans le système de types.
D'une part, selon les mêmes règles de sous-typage mentionnées ci-dessus, il est très probable que cela fonctionne déjà pour ce que vous voulez faire. Par exemple
Rien n'empêche les implémentations de cette classe de recevoir tout type d'animal, en tant que tel il répond déjà aux critères de votre question.
Mais supposons que nous pourrions remplacer cette méthode comme vous l'avez suggéré:
Voici la partie amusante, maintenant vous pouvez le faire:
Selon l'interface publique de
AnimalHunter
vous, vous devriez pouvoir chasser n'importe quel animal, mais selon votre implémentation,MammutHunter
vous n'acceptez que desMammut
objets. Par conséquent, la méthode remplacée ne satisfait pas l'interface publique. Nous venons de rompre la solidité du système de type ici.Vous pouvez implémenter ce que vous voulez en utilisant des génériques.
Ensuite, vous pouvez définir votre MammutHunter
Et en utilisant la covariance et la contravariance génériques, vous pouvez assouplir les règles en votre faveur si nécessaire. Par exemple, nous pourrions nous assurer qu'un chasseur de mammifères ne peut chasser des félins que dans un contexte donné:
Supposons des
MammalHunter
outilsAnimalHunter<Mammal>
.Dans ce cas, cela ne serait pas accepté:
Même lorsque les mammuts sont des mammifères, cela ne serait pas accepté en raison des restrictions sur le type contravariant que nous utilisons ici. Donc, vous pouvez toujours exercer un certain contrôle sur les types pour faire des choses comme celles que vous avez mentionnées.
la source
Le problème n'est pas ce que vous faites dans la méthode prioritaire avec l'objet donné en argument. Le problème est quel est le type d'arguments que le code utilisant votre méthode est autorisé à alimenter à votre méthode.
Une méthode prioritaire doit respecter le contrat de la méthode substituée. Si la méthode substituée accepte des arguments d'une classe et que vous la remplacez par une méthode qui n'accepte qu'une sous-classe, elle ne remplit pas le contrat. C'est pourquoi il n'est pas valable.
La surcharge d'une méthode avec un type d'argument plus spécifique est appelée surcharge . Il définit une méthode avec le même nom mais avec un type d'argument différent ou plus spécifique. Une méthode surchargée est disponible en plus de la méthode d'origine. La méthode appelée dépend du type connu au moment de la compilation. Pour surcharger une méthode, vous devez supprimer l'annotation @Override.
la source