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é.

capture

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?

54
demandé sur Lonely Neuron 2018-04-25 07:29:18

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");
    }
}
66
répondu ernest_k 2018-04-25 04:49:34

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"
    }
}
23
répondu Codebender 2018-09-05 10:48:19

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.

7
répondu Lonely Neuron 2018-09-05 10:50:41

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());.

0
répondu Arun Sudhakaran 2018-04-25 05:04:18

GetWorkDetail (this) ne sait pas quelles sont les sous-classes. appelez getWorkDetail à la place.

-4
répondu Ray Tayek 2018-04-25 04:33:25