在Java中调用哪个重载方法

时间:2018-04-25 04:29:18

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

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

main方法只创建一个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,它会在Person中调用重载方法,该方法将Employee作为参数。由于我明显错误,我打开了一个调试器,假设引用了"这个"在getWorkDetail(this)类的Person行必须变形为超级类。然而,这不是我发现的。

screenshot

显然,代码this中的这一点是Employee对象,但它仍然选择执行重载方法getWorkDetail(Person p)。任何人都可以解释这种行为吗?

5 个答案:

答案 0 :(得分:69)

与方法覆盖不同,方法重载基于静态类型链接。在这种情况下,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");
    }
}

答案 1 :(得分: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"
    }
}

答案 2 :(得分:7)

特定问题的解决方案

在某些语言中,参数被解析为其动态类型,但不是在java中。编译器已在编译时确定您的getWorkDetail(this);将去哪里。 this的类型为Person,因此调用getWorkDetail(Person e)。在您的具体情况下,解决方案非常明显。正如其他人已经指出的那样,您需要覆盖getWorkDetail()类中的Employee

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

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

如果您有两个不同的类,则无法再实现上述简单的解决方案。在这些情况下,您必须使用visitor pattern

考虑以下课程:

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!"

按照访问者模式调用Animal.eat会调用Food.eatenByMeatVegetables都会实现。这些类将调用更具体的eatMeateatVegetables方法,该方法使用正确的(动态)类型。

答案 3 :(得分:0)

通话偏好

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

然后在main方法中尝试像testChild一样调用testChild(new FooChild());

答案 4 :(得分:-4)

getWorkDetail(this)不知道子类是什么。改为调用getWorkDetail。