56 votes

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");
    }
}

Les éléments suivants Employee étend la classe Person classe 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 Employee (à la fois de type statique et dynamique) et appelle .work() sur elle :

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 cela, j'avais pensé que puisque le type statique et dynamique de l'objet e1 es Employee il appellerait la méthode surchargée de Person qui prend une valeur de Employee en tant que paramètre. Puisque je me trompe clairement à ce sujet, j'ai ouvert un débogueur en supposant que la référence à "ceci" à la ligne getWorkDetail(this) dans le Person doit s'être transformée en sa super classe. Cependant, ce n'est pas ce que j'ai trouvé.

screenshot

Il est clair qu'à ce stade du code this est un Employee mais elle a quand même choisi d'exécuter la méthode surchargée getWorkDetail(Person p) . Quelqu'un peut-il expliquer ce comportement ?

36 votes

IMHO, la classe parent ne devrait rien savoir des classes enfants. Je veux dire par là qu'il n'y a pas de place dans l'architecture de l Person classe pour getWorkDetail(Employee e) méthode...

1 votes

@zlakad Je pense que ces fonctions étaient censées être statiques ?

0 votes

@StarWeaver, statique ou non, quelle est la différence dans cette question particulière ?

72voto

ernest_k Points 14807

Contrairement aux surcharges de méthodes, les surcharges de méthodes sont liées en fonction du type statique. Et dans ce cas, getWorkDetail(this) en Person ne connaît que le Person type.

La surcharge de méthodes n'est pas conçue pour fournir un comportement dynamique à l'exécution.

Pour tirer parti de la liaison dynamique, vous devrez peut-être remanier votre code pour remplacer les méthodes par d'autres :

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 des classes d'implémentation. Bien sûr, vous pouvez surcharger des méthodes, à condition de prendre soin de surcharger également les méthodes surchargées, 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");
    }
}

1 votes

@Ernest Kiwele Merci ! Je ne savais pas que Java ne fournit pas de comportement dynamique pour les surcharges de méthodes. Cela clarifie les choses.

2 votes

Vous pouvez également noter que la JVM recherche d'abord les méthodes non surchargées qui ont la signature que vous spécifiez avant de rechercher les méthodes surchargées qui correspondent à votre signature. Mais idéalement, vous voulez tirer parti du mécanisme d'héritage de Java pour restructurer votre code comme le montre @Ernest.

26voto

Codebender Points 6087

La résolution des surcharges se fait au moment de la compilation, et non au moment de l'exécution.

Donc, quand vous appelez getWorkDetails(this) , this est supposé être un Person (qui est le type statique) et donc appelé la surcharge correspondante.

Remarque : L'utilisation de this à l'intérieur de Employee aurait fait de cette classe un Employee type. Vous pouvez le vérifier en surchargeant work() en Employee comme ça.

class Employee extends Person {
    ...

    public void work() {
        getWorkDetails(this); // This should print "This person is an Employee"
    }
}

7voto

Lonely Neuron Points 2839

Solution spécifique au problème

Dans certains langages, les paramètres sont résolus en fonction de leur type dynamique, mais pas en java. Le compilateur détermine déjà au moment de la compilation où se trouve votre paramètre 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 devez remplacer getWorkDetail() dans le Employee classe.

Résoudre les méthodes en fonction de leurs types de paramètres dynamiques

Pour résoudre le problème général de la résolution des types de paramètres au moment de l'exécution, l'utilisation de la fonction instanceof est à éviter, car il conduit généralement à un code malpropre.

Si vous avez deux classes différentes, une solution aussi simple que celle présentée ci-dessus n'est plus possible. Dans ce cas, vous devrez utiliser la fonction schéma de visite .

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 ça :

Animal animal = new Shark();
Food someMeat = new Meat();
Food someVegetables= new Vegetables();
animal.eat(someMeat);        // prints "Tasty meat!"
animal.eat(someVegetables);  // prints "Yuck!"

Suite à la schéma de visite en appelant Animal.eat appellera Food.eatenBy qui est mis en œuvre à la fois par Meat y Vegetables . Ces classes feront appel à la méthode plus spécifique eatMeat o eatVegetables qui utilise les types (dynamiques) corrects.

0voto

Arun Sudhakaran Points 1229

Préférence d'appel

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 le premier test() et voir quel est le résultat.

C'est l'hirarchie de préférence dans les types de données primitifs. Pour en venir aux types dérivés, il faut déclarer une classe FooChild comme ceci

class FooChild extends Foo {

}

et créer 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"); }

puis dans la méthode principale, essayez d'appeler testChild comme ceci testChild(new FooChild()); .

-4voto

Ray Tayek Points 4635

GetWorkDetail(this) ne sait pas quelles sont les sous-classes. Appelez plutôt getWorkDetail.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X