Какой перегруженный метод вызывается в Java



у меня есть базовая ситуация наследования с перегруженным методом в суперклассе.



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


следующее Employee класс расширяет Person классом выше:



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


основной метод просто создает Employee объект (как статический, так и динамический тип) и вызовы .work() на:



public static void main(String[] args){
Employee e1 = new Employee("Manager1", 1976, "Female");
e1.work();
}


это заканчивается печатью




This person is not an Employee




просматривая это, я думал, что так как оба статический и динамический тип объекта e1 и Employee он будет вызывать перегруженный метод лично, который принимает Employee в качестве параметра. Поскольку я явно ошибаюсь в этом, я открыл отладчик, предполагая ссылку на " это " в строке getWorkDetail(this) на Person класс, должно быть, превратился в супер класс. Однако это не то, что я нашел.



screenshot



ясно в этот момент в коде this это Employee объект, однако он все же решил выполните перегруженный метод getWorkDetail(Person p). Кто-нибудь может объяснить такое поведение?

623   5  

5 ответов:

В отличие от переопределений методов, перегрузки методов связаны на основе статического типа. И в этом случае, getWorkDetail(this) на Person только знает о Person тип.

перегрузка метода не предназначена для обеспечения динамического поведения во время выполнения.

чтобы воспользоваться динамической привязкой, вам может потребоваться изменить свой код, чтобы переопределить методы, вместо этого:

public static void main(String[] args) throws IOException {
    new Employee("Manager1", 1976, "Female").getWorkDetail();
    new Person("Manager1", 1976, "Female").getWorkDetail();
}

и изменить поведение на основе реализации классов. Конечно, вы можете перегружать методы, как если вы также позаботитесь о переопределении перегруженных методов, если это необходимо.

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

разрешение перегрузки происходит во время компиляции, а не во время выполнения.

Итак, когда вы звоните getWorkDetails(this),this считается Person (который является статическим типом) и поэтому называется соответствующей перегрузкой.

Примечание: С Помощью this внутри Employee класс сделал бы его Employee тип. Вы можете проверить это, перегружая work() на Employee такой.

class Employee extends Person {
    ...

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

конкретное решение проблемы

в некоторых языках параметры разрешаются к их динамическому типу, но не в java. Компилятор уже определяет во время компиляции, где ваш getWorkDetail(this); пойдет. this типа Person, так что getWorkDetail(Person e) называется. В вашем конкретном случае решение вполне очевидно. Как уже указывали другие, вам нужно будет переопределить getWorkDetail() на Employee класса.

методы разрешения для их динамического параметра типы

для решения общей проблемы разрешения типы параметров во время выполнения, используя instanceof оператора следует избегать, так как это обычно приводит к нечистому коду.

если у вас есть два разных класса, решение, столь простое, как указано выше, больше невозможно. В этих случаях вам придется использовать шаблон Visitor.

рассмотрим следующие классы:

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

который вы можете назвать как это:

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

после шаблон Visitor вызов Animal.eat будем называть Food.eatenBy, который реализуется как Meat и Vegetables. Эти классы будут называть более конкретные eatMeat или eatVegetables метод, который использует правильные (динамические) типы.

предпочтение вызовов

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

выход будет int печатается на консоль. Теперь вы комментируете первый test() метод и посмотреть, что на выходе идет.

это предпочтение hirarchey в примитивных типах данных. Теперь перейдем к производным типам объявить класс FooChild такой

class FooChild extends Foo {

}

и создать два новых метода в Foo как

static void testChild(Foo foo) { System.out.println("Foo"); }
static void testChild(FooChild fooChild) { System.out.println("FooChild"); }

затем в основном методе попробуйте вызвать testChild такой testChild(new FooChild());.

getWorkDetail (this) не знает, что такое подклассы. вместо этого вызовите getWorkDetail.

Comments

    Ничего не найдено.