La surcharge en Java et plusieurs d'expédition
J'ai une collection (de liste ou de tableau ou de liste) dans lequel je veux mettre les deux valeurs de Chaîne et les valeurs doubles. J'ai décidé de faire une collection d'objets et à l'aide de la surcharge ond polymorphisme, mais j'ai fait quelque chose de mal.
Je lance un petit test:
public class OOP {
void prova(Object o){
System.out.println("object");
}
void prova(Integer i){
System.out.println("integer");
}
void prova(String s){
System.out.println("string");
}
void test(){
Object o = new String(" ");
this.prova(o); //Prints 'object'!!! Why?!?!?
}
public static void main(String[] args) {
OOP oop = new OOP();
oop.test(); //Prints 'object'!!! Why?!?!?
}
}
Dans le test semble que le type d'argument est décidé au moment de la compilation et non à l'exécution. Pourquoi est-ce?
Cette question est liée à:
Polymorphisme vs Primordial vs Surcharge
Essayez de décrire le polymorphisme aussi facile que vous le pouvez
EDIT:
Ok la méthode à appeler est décidé au moment de la compilation. Est-il une solution pour éviter d'utiliser le instanceof
opérateur?
- Parce que c'est la façon dont Java surcharge de travaux.
- Mais cet objet est une Chaîne de caractères au moment de l'exécution, et il y a une méthode définie pour les chaînes. Ce que je fais mal?
- Vous êtes en supposant que le choix de la surcharge d'appel est fait au moment de l'exécution. Il n'est pas; c'est décidé au moment de la compilation, basé sur le type statique de l'argument.
- Primordial est dynamique, mais la surcharge est statique. C'est un choix de conception.
- Je vous remercie. Comment puis-je faire pour décider au moment de l'exécution de la méthode qui appelle t-il?
- Utiliser le polymorphisme 🙂 ou des habitudes des visiteurs pour la répartition multiple.
Vous devez vous connecter pour publier un commentaire.
Ce post secondes voo réponse, et donne des détails sur les solutions alternatives à la liaison tardive.
Général Jvm utiliser uniquement seul envoi: le runtime type est prise en compte uniquement pour le récepteur de l'objet; pour les paramètres de la méthode, le type statique est considéré comme. Une mise en œuvre efficace avec les optimisations est très facile à l'aide la méthode des tables de (qui sont similaires à C++de tables virtuelles). Vous pouvez trouver plus de détails par exemple dans le HotSpot Wiki.
Si vous voulez la répartition multiple pour vos paramètres, prendre un coup d'oeil à
this.resend(...)
au lieu desuper(...)
d'invoquer le plus spécifique de la méthode de remplacement de la enfermant méthode;Si vous voulez bâton avec Java, vous pouvez
Valeur expédition:
Ce que vous voulez, c'est le double ou plus général la répartition multiple, quelque chose qui est réellement mis en œuvre dans d'autres langues (common lisp vient à l'esprit)
Sans doute la raison principale de java ne l'a pas, c'est parce qu'il arrive à un rendement de pénalité parce que la résolution de surcharge doit être fait au moment de l'exécution et pas le temps de compilation. La manière habituelle, c'est la modèle visiteur - assez laid, mais c'est comment il est.
Lors de l'appel d'une méthode qui est surchargé, Java choisit le plus restrictif type en fonction du type de la variable passé à la fonction. Il n'utilise pas le type de l'instance réelle.
Vieille question mais pas de réponse apporte une solution concrète en Java pour résoudre le problème de façon propre.
En effet, pas facile, mais très intéressante question. Voici ma contribution.
Comme dit dans l'excellent @DaveFar réponse, Java ne supporte que la seule méthode dispatch.
Dans cette expédition de mode, le compilateur les limites de la méthode à invoquer dès que la compilation en s'appuyant sur la déclaration de types de paramètres et de ne pas leur exécution types.
Pour résoudre la réponse de manière propre et l'utilisation d'un double envoi, il nous faut faire abstraction de la manipuler des données.
Pourquoi ?
Ici un naïf visiteur approche pour illustrer le problème :
Maintenant, la question : comment visité les classes peuvent invoquer la
visit()
méthode ?La deuxième expédition de la double envoi de la mise en œuvre s'appuie sur le" contexte de la classe qui accepte d'être visité.
Donc nous avons besoin d'un
accept()
méthode dansInteger
,String
etObject
classes pour effectuer cette deuxième expédition :Mais impossible ! Visité les classes sont intégrés dans les classes :
String
,Integer
,Object
.Donc nous n'avons aucun moyen d'ajouter cette méthode.
Et de toute façon, nous ne voulons pas ajouter que.
Afin de mettre en œuvre la double expédition, nous devons être en mesure de modifier les classes que nous voulons faire passer comme paramètre dans la deuxième expédition.
Ainsi, au lieu de manipuler
Object
etList<Object>
comme type déclaré, nous allons manipulerFoo
etList<Foo>
où laFoo
classe est un wrapper de la tenue de la valeur pour l'utilisateur.Ici est la
Foo
interface :getValue()
renvoie la valeur pour l'utilisateur.Il spécifie
Object
comme type de retour, mais Java prend en charge la covariance des rendements (depuis la version 1.5), de sorte que nous pourrions définir de façon plus spécifique de type pour chaque sous-classe d'éviter downcasts.ObjectFoo
StringFoo
IntegerFoo
Ici est la DisplayVisitor classe de visiter
Foo
sous-classes :Et voici un exemple de code pour tester la mise en œuvre :
De sortie :
L'amélioration de la mise en œuvre
La mise en œuvre effective nécessite l'introduction d'un wrapper de la classe pour chaque buit-dans le type que nous voulons pour l'envelopper.
Tel que discuté, nous n'avons pas le choix à opérer un double envoi.
Mais notez que le code à répétition dans Foo sous-classes pourraient être évités :
On pourrait en effet présenter un résumé de classe générique qui contient la valeur pour l'utilisateur et fournit un accesseur pour :
Maintenant
Foo
sublasses sont plus légers à déclarer :Et la
test()
méthode devrait être modifié pour déclarer un type générique (?
) pour laFoo
type dans leList<Foo>
déclaration.En fait, si vraiment nécessaire, nous pourrions simplifier encore plus
Foo
sous-classes en introduisant la génération de code java.De déclarer cette sous-classe :
pourrait aussi simple que la déclaration d'une classe et l'ajout d'une annotation sur:
Où
Foo
est une coutume annotation traitées au moment de la compilation.ce n'est pas polymoprhism, vous avez tout simplement en surcharge d'une méthode et l'a appelé avec le paramètre de type d'objet
Tout en Java est un
Object
/objet (sauf les types primitifs). Vous stocker des chaînes et des nombres entiers comme des objets, et puis comme vous l'appelez leprove
méthode qu'ils sont encore considérés comme des objets. Vous devriez jeter un oeil à lainstanceof
mot-clé. Suivez ce lien