Je sais que ce n'est pas possible, mais est-ce que quelqu'un peut expliquer pourquoi Java a choisi de ne pas supporter cela? Je pose la question parce que je viens de me trouver dans une situation où je pense que ce serait bien d’avoir.
Etant donné que vous n'êtes pas obligé de capturer la valeur de retour d'une méthode en Java, le compilateur ne peut alors pas décider quelle surcharge utiliser. Par exemple.
boolean doSomething() { ... }
int doSomething() { ... }
doSomething(); // which one to call???
Un aspect intéressant de cette question est le fait que le langage Java interdit les méthodes de surcharge uniquement par type de retour. Mais pas la JVM:
Notez qu’il peut y avoir plus d’une méthode de correspondance Dans une classe car Alors que le langage Java interdit à une classe De déclarer plusieurs méthodes avec La même signature, mais types de retour différents, pas la machine virtuelle Java . Cette flexibilité accrue De la machine virtuelle peut être utilisée pour Implémenter diverses fonctionnalités de langage. Par exemple, les retours covariants peuvent être Implémentés avec des méthodes de pont; la méthode de pontage et la méthode dont remplacés auraient la même signature mais des types de retour différents.
Je me suis demandé pourquoi ils ne soutiennent pas cela aussi. Bien sûr, si vous ignorez la valeur de retour, le compilateur n'aura aucun moyen de savoir ce que vous voulez. Mais c’est la même ambiguïté qui se pose avec les valeurs nulles qui passent. Comme:
String doSomething(String s) { ... }
String doSomething(Integer s) { ... }
...
String out=doSomething(null);
Dans ce cas, le compilateur se plaint simplement que l'appel est ambigu, et vous devez le résoudre en transmettant la valeur null, comme suit:
String out=doSomething((String)null);
Vous pouvez faire la même chose avec la surcharge par type de retour:
String getSomething() { ... }
Integer getSomething() { ... }
...
Integer n=getSomething();
probablement appeler la deuxième fonction.
getSomething();
serait ambigu (et dans cet exemple, probablement inutile, à moins d’avoir des effets secondaires, mais c’est une autre histoire), vous devrez donc dire:
(String) getSomething();
Plus réaliste, peut-être:
if ((String) getSomething()==null) ...
Mais c'est le cas facile. Je peux voir un auteur-compilateur qui ne veut pas supporter cela parce que cela peut devenir très compliqué à comprendre autrement que par une simple affectation. Par exemple, considérons:
String getSomething() { ... };
Integer getSomething() { ... };
String getOtherthing() { ... };
...
if (getSomething().equals(getOtherthing())) ...
Le compilateur devrait comprendre que String et Integer ont des fonctions égales, donc l’un ou l’autre est valide à ce stade. Ensuite, il faudrait remarquer que getOtherthing est une chaîne et qu'Integer.equals (String) est peu probable. Par conséquent, l'auteur souhaitait probablement String.equals (String). C'est faisable, mais à ce moment-là, je commence à voir que dans le cas général, cela pourrait être une bête.
Et puis supposons que nous ajoutons:
Integer getOtherthing() { ... };
Maintenant, que fait le compilateur avec cette instruction IF? Il pourrait utiliser les versions String des deux fonctions, ou l'entier, mais pas la chaîne de l'une et l'entier de l'autre. À ce stade, il devrait insister sur un casting pour le dire, je suppose. Mais la complexité devient vraiment hors de contrôle.
Et si le compilateur a du mal à comprendre ce que vous voulez vraiment dire, imaginez ce que ce serait pour un autre programmeur qui ne peut pas rechercher toutes les signatures de fonction aussi rapidement que le compilateur.
C'est parce que vous êtes libre d'ignorer la valeur de retour.
Bien que cela soit théoriquement possible, il n'a pas été utilisé en Java pour la même raison qu'il ne l'était pas en C++; à savoir, il a été constaté que les surcharges basées sur les types de retour sont généralement plus source de confusion pour les développeurs, le bénéfice est marginal comparé aux coûts de son implémentation, et il serait ambigu dans le cas où le type de retour n'est pas attribué à un valeur. Pour ces raisons, la surcharge basée sur le type de retour n'est pas prise en charge.
Je pense que l'une des raisons est que, dans la plupart des cas, vous ne pouvez déterminer le type de retour d'une fonction qu'après l'exécution de la fonction plutôt qu'avant ce processus. Ainsi, cela ne peut pas vous aider à choisir la fonction surchargée à invoquer en fonction de différents types de fonctions de retour.
La surcharge de méthode utilise la technique de polymorphisme à la compilation. La méthode utilise une technique de polymorphisme au moment de l’exécution.
Surcharge de méthode:
Comme indiqué dans les réponses précédentes, Java ne prend pas en charge la surcharge de méthodes avec un type de retour différent et les mêmes arguments. En effet, il doit déterminer quelle méthode utiliser au moment de la compilation. Pour lever l'ambiguïté, ils ont conçu la technique de surcharge de méthode comme ceci.
Si nous avons vraiment besoin de surcharger une méthode avec différents types et mêmes arguments, il est possible dans une certaine mesure avec la méthode mehtod de remplacer.
Méthode annulant:
La méthode surchargée utilise la technique de polymorphisme au moment de l'exécution. Par conséquent, la méthode à exécuter n'est pas décidée au moment de la compilation et elle est décidée au moment de l'exécution par la machine virtuelle Java.
Avec les types de retour co-variant, nous pouvons avoir différents types de retour dans la méthode de la sous-classe avec les mêmes arguments que la classe de base.
Exemple de type de retour co-variant:
class BaseClass {
BaseClass dosomething(){
System.out.println("Print BaseClass");
return this;
}
}
class AnotherBaseClass extends BaseClass {
@Override
BaseClass dosomething(){
System.out.println("Print AnotherBaseClass");
return this;
}
}
class SubClass extends AnotherBaseClass {
@Override
SubClass dosomething(){ /*Here SubClass is co-vairantreturn type*/
System.out.println("Print SubClass");
return this;
}
public static void main(String args[]){
SubClass s1 = new SubClass();
s1.dosomething();
}
}
Sortie:
Sous-classe d'impression
surcharger la fonction uniquement sur la base du type de retour est source de confusion pour le compilateur afin de distinguer les appels, car au moment de l'appel, vous ne donnez pas le type de retour, comme dans le cas des paramètres, vous ne donnez donc que la liste de paramètres et cette liste de paramètres est le seul moyen pour le compilateur de faire la distinction entre les appels de fonction, et la valeur renvoyée est reçue à l'achèvement de la fonction, c'est pourquoi le type de renvoi ne contribue pas à la signature de la fonction