Quelle méthode surchargée est appelée en Java
J'ai une situation d'héritage de base avec une méthode surchargée dans la super classe.
public class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex){
name = theName;
dob = birth;
gender = sex;
}
public void work(){
getWorkDetail(this);
}
public void getWorkDetail(Employee e){
System.out.println("This person is an Employee");
}
public void getWorkDetail(Person p){
System.out.println("This person is not an Employee");
}
}
La classe Employee
suivante étend la classe Person
ci-dessus:
public class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex){
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
}
La méthode principale crée simplement un objet Employee
(type statique et dynamique) et appelle .work()
sur celui-ci:
public static void main(String[] args){
Employee e1 = new Employee("Manager1", 1976, "Female");
e1.work();
}
Cela finit par Imprimer
This person is not an Employee
En regardant à travers cela, j'avais pensé que puisque le type statique et dynamique de l'objet e1
est Employee
Il appellerait la méthode surchargée en personne qui prend un Employee
comme paramètre. Puisque je me trompe clairement à ce sujet, j'ai ouvert un débogueur en supposant que la référence à "this" à la ligne getWorkDetail(this)
dans la classe Person
doit avoir changé en sa super classe. Cependant, ce n'est pas ce que j'ai trouvé.
Clairement à ce stade du code this
est un objet Employee
, mais il a toujours choisi d'exécuter la méthode surchargée getWorkDetail(Person p)
. Quelqu'un peut expliquer ce comportement?
5 réponses
Contrairement aux remplacements de méthode, les surcharges de méthode sont liées en fonction du type statique. Et dans ce cas, getWorkDetail(this)
dans Person
ne connaît que le type Person
.
La surcharge de méthode n'est pas conçue pour fournir un comportement d'exécution dynamique.
Pour profiter de la liaison dynamique, vous devrez peut-être redessiner votre code pour remplacer les méthodes, à la place:
public static void main(String[] args) throws IOException {
new Employee("Manager1", 1976, "Female").getWorkDetail();
new Person("Manager1", 1976, "Female").getWorkDetail();
}
Et modifier le comportement en fonction de l'implémentation des classes. Bien sûr, vous pouvez surcharger les méthodes, tant que vous prenez soin de surcharger les méthodes surchargées aussi, si nécessaire.
class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex) {
name = theName;
dob = birth;
gender = sex;
}
public void getWorkDetail() {
System.out.println("This person is not an Employee");
}
}
class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex) {
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
public void getWorkDetail() {
System.out.println("This person is an Employee");
}
}
La résolution de surcharge se produit pendant la compilation, pas au moment de l'exécution.
Ainsi, lorsque vous appelez getWorkDetails(this)
, this
est supposé être un Person
(qui est le type statique), et donc appelé le correspondant de surcharge.
Note: L'utilisation de this
à l'intérieur de la classe Employee
en aurait fait un type Employee
. Vous pouvez le vérifier en surcharge work()
dans Employee
comme ceci.
class Employee extends Person {
...
public void work() {
getWorkDetails(this); // This should print "This person is an Employee"
}
}
Solution spécifique au problème
Dans certains langages, les paramètres sont résolus à leur type dynamique, mais pas en java. Le compilateur détermine déjà au moment de la compilation où votre getWorkDetail(this);
ira. this
est de type Person
, donc getWorkDetail(Person e)
est appelé. Dans votre cas spécifique, la solution est assez évidente. Comme d'autres l'ont déjà souligné, vous devrez remplacer getWorkDetail()
dans la classe Employee
.
Résolution des méthodes à leurs types de paramètres dynamiques
Pour résoudre le problème général de la résolution des types de paramètres à l'exécution, en utilisant l'opérateur instanceof
doit être évitée, car elle conduit généralement à un code impur.
Si vous avez deux classes différentes, une solution aussi simple que celle indiquée ci-dessus n'est plus possible. Dans ces cas, vous aurez à utiliser le modèle visiteur.
Considérons les classes suivantes:
public interface Animal {
default void eat(Food food) {
food.eatenBy(this);
}
void eatMeat(Meat meat);
void eatVegetables(Vegetables vegetables);
}
public class Shark implements Animal {
public void eatMeat (Meat food) {
System.out.println("Tasty meat!");
}
public void eatVegetables (Vegetables food) {
System.out.println("Yuck!");
}
}
public interface Food {
void eatenBy(Animal animal);
}
public class Meat implements Food {
public void eatenBy(Animal animal) {
animal.eatMeat(this);
}
}
public class Vegetables implements Food {
public void eatenBy(Animal animal) {
animal.eatVegetables(this);
}
}
Que vous pouvez appeler comme ceci:
Animal animal = new Shark();
Food someMeat = new Meat();
Food someVegetables= new Vegetables();
animal.eat(someMeat); // prints "Tasty meat!"
animal.eat(someVegetables); // prints "Yuck!"
Suivant le modèle visiteur appelant Animal.eat
appellera Food.eatenBy
, qui est implémenté à la fois par Meat
et Vegetables
. Ces classes appelleront la méthode eatMeat
ou eatVegetables
plus spécifique, qui utilise les types (dynamiques) corrects.
Appeler de préférence
class Foo {
static void test(int arg) { System.out.println("int"); }
static void test(float arg) { System.out.println("float"); }
static void test(Integer arg) { System.out.println("Integer"); }
static void test(int... arg) { System.out.println("int..."); }
public static void main(String[] arg) {
test(6);
}
}
, La sortie sera int imprimé sur la console. Maintenant, vous commentez la première méthode test()
et voyez quelle est la sortie à venir.
C'est la préférence hirarchey dans les types de données primitifs. Maintenant, en venant aux types dérivés, déclarez une classe FooChild
comme ceci
class FooChild extends Foo {
}
Et créez deux nouvelles méthodes dans Foo
comme
static void testChild(Foo foo) { System.out.println("Foo"); }
static void testChild(FooChild fooChild) { System.out.println("FooChild"); }
Ensuite, dans la méthode principale, essayez d'appeler testChild
comme ceci testChild(new FooChild());
.
GetWorkDetail (this) ne sait pas quelles sont les sous-classes. appelez getWorkDetail à la place.