在Java中调用哪个重载方法

Eri*_*c S 56 java inheritance overloading

我有一个基本的继承情况与超类中的重载方法.

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

以下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;
    }
}
Run Code Online (Sandbox Code Playgroud)

main方法只是创建一个Employee对象(静态和动态类型)并调用.work()它:

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

这最终打印

This person is not an Employee

期待通过这个我想,既然静态和动态类型的对象e1Employee它会调用亲自重载方法接受一个Employee作为参数.因为我对此明显错误,所以我打开了一个调试器,假设getWorkDetail(this)Person类中的行中对"this"的引用必须已经变形为它的超类.然而,这不是我发现的.

截图

显然,代码this中的这一点是一个Employee对象,但它仍然选择执行重载方法getWorkDetail(Person p).谁能解释这种行为?

ern*_*t_k 70

与方法覆盖不同,方法重载基于静态类型链接.在这种情况下,getWorkDetail(this)Person只知道的Person类型.

方法重载不是为了提供动态运行时行为而设计的.

要利用动态绑定,您可能需要重新设计代码以覆盖方法,而不是:

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

并根据实现类修改行为.当然,您可以重载方法,只要您负责覆盖重载方法,如果需要的话.

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 此外,您可能需要注意的是,在查找与您的签名匹配的重写方法之前,JVM首先会查找具有您指定的签名的非重写方法.但理想情况下,您希望利用Java的继承机制来重构代码,就像@Ernest所示 (2认同)

Cod*_*der 23

重载解析在编译期间发生,而不是在运行时.

因此,当您调用时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"
    }
}
Run Code Online (Sandbox Code Playgroud)


Neu*_*ron 7

特定问题解决方案

在某些语言中,参数被解析为其动态类型,但不是在java中.编译器已经在编译时确定了您的getWorkDetail(this);意愿.this属于类型Person,因此getWorkDetail(Person e)被称为.在您的具体情况下,解决方案非常明显.正如其他人已经指出的那样,你需要getWorkDetail()Employee课堂上重写.

解析其动态参数类型的方法

要解决在运行时解析参数类型的一般问题,instanceof应避免使用运算符,因为它通常会导致不干净的代码.

如果您有两个不同的类,则无法再实现上述简单的解决方案.在这些情况下,您将不得不使用访问者模式.

考虑以下类:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以这样打电话:

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

跟随访问者模式调用Animal.eat将调用Food.eatenBy,这由两者MeatVegetables.实现.这些类将调用更具体eatMeateatVegetables方法,它使用正确的(动态)类型.