Salut,
C'est une question interressante car il y a plusieurs concepts mis en oeuvre.
Dans un premier temps il faut savoir que les types primaires sont convertit automatiquement vers un type plus grand lorsque cela s'avère neccessaire. Par exemple si une méthode attend un double, tu pourras lui passer un short, un int, un long ou un float sans que cela ne provoque d'erreur ou de warning : la valeur est automatiquement convertit en double. L'inverse n'est pas vrai car on pourrait alors avoir une perte de précision...
Enfin les signatures des méthodes en Java sont définis par deux éléments :- son nom.
- le nombre et le type de ses paramètres.
Ainsi, dans ton premier exemple, tu as deux méthodes distinctes f(long) et f(double), même si elle ont le même nom. On parle alors de surcharge (overload en anglais).
Donc d'après l'héritage, la classe A ne possède qu'une méthode f(double), alors que la classe C possède les méthodes f(long) et f(double) (qu'elle hérite directement de A).
Pour comprendre le résultat que tu obtiens, il faut comprendre le principe le la compilation. Lorsque tu compiles ton code, le compilateur recherche la signature de méthode qui sera appellée en se basant sur le type déclaré de la variable (il y a un nom exact pour cela mais je ne m'en souviens plus ).
Ainsi lorsques tu compile le code suivant :
C c=new C(); c.f(bb);c.f(q);c.f(x);
Comme c est déclaré en tant que C, le compilateur a le choix d'utiliser f(long) ou f(double), ce qu'il fera selon le type du paramètre que tu lui passes...
Mais lorsque tu compiles ce code :
A a = c; a.f(bb);a.f(q);a.f(x);
Comme a est déclaré en tant que A, le compilateur a un seul et unique choix : la méthode f(double) ! Donc il appelera forcément cette dernière et convertira automatiquement les types en double...
Le compilateur ne se base en aucun cas sur le type réel de l'objet mais uniquement sur son type déclaré. En effet, il ne peut pas forcément connaitre le type réel de l'objet.
Dans ton second exemple par contre, tu n'a qu'un seul et unique méthode affiche(), puisque son nom et ses "paramètres" sont identique. On parle ici de redéfinition de méthode par une classe fille (override en anglais).
Donc ici dans tous les cas le compilateur va "appeller" la méthode affiche().
La différence se situe alors à l'exécution. En java toutes les méthodes sont virtual par défaut. C'est à dire que la JVM recherchera la vrai méthode à appeller à l'exécution en cas de redéfinition. Ainsi lorsque la JVM exécute le code suivant :
C c = new C(); c.affiche();
Le compilateur demande d'exécuter la méthode affiche() sur un objet du type C.
A l'exécution la JVM vérifie le type exact (qui est bien C) et appelle la méthode affiche() de C --> "Je suis C".
Mais lorsque tu exécutes ceci :
Le compilateur demande d'exécuter la méthode affiche() sur un objet du type A.
A l'exécution la JVM vérifie le type exact (qui est C et non A) et appelle la méthode affiche() de C --> "Je suis C".
Je ne sais pas si je suis bien clair... n'hésites pas a demander des détails
a++
Partager