我有一个基本的继承情况与超类中的重载方法 .
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();
}
这最终打印
此人不是员工
通过这个看,我原以为由于对象 e1
的静态和动态类型都是 Employee
,它会调用Person中的重载方法,该方法将 Employee
作为参数 . 由于我对此明显错误,我打开了一个调试器,假设在 Person
类的 getWorkDetail(this)
行的"this"的引用必须已经变形为它的超类 . 然而,这不是我发现的 .
显然,在代码中 this
是一个 Employee
对象,但它仍然选择执行重载方法 getWorkDetail(Person p)
. 谁能解释这种行为?
5 回答
与方法覆盖不同,方法重载基于静态类型链接 . 在这种情况下,
Person
中的getWorkDetail(this)
只知道Person
类型 .方法重载不是为了提供动态运行时行为而设计的 .
要利用动态绑定,您可能需要重新设计代码以覆盖方法,而不是:
并根据实现类修改行为 . 当然,您可以重载方法,只要您负责覆盖重载方法,如果需要的话 .
重载解析在编译期间发生,而不是在运行时 .
因此,当您调用
getWorkDetails(this)
时,this
被假定为Person
(这是静态类型),因此称为相应的重载 .注意:在
Employee
class中使用this
会使它成为Employee
类型 . 您可以通过在Employee
中重载work()
来验证这一点 .特定于问题的解决方案
在某些语言中,参数被解析为其动态类型,但不是在java中 . 编译器已经在编译时确定了
getWorkDetail(this);
将要去的地方 .this
的类型为Person
,因此调用getWorkDetail(Person e)
. 在您的具体情况下,解决方案非常明显 . 正如其他人已经指出的那样,你需要在Employee
类中覆盖getWorkDetail()
.解析其动态参数类型的方法
要解决在运行时解析参数类型的一般问题,应避免使用
instanceof
运算符,因为它通常会导致不干净的代码 .如果您有两个不同的类,则无法再实现上述简单的解决方案 . 在这些情况下,您将不得不使用visitor pattern .
考虑以下类:
你可以这样打电话:
在 visitor pattern 之后调用
Animal.eat
将调用Food.eatenBy
,它由Meat
和Vegetables
实现 . 这些类将调用更具体的eatMeat
或eatVegetables
方法,该方法使用正确的(动态)类型 .Call preference
输出将在控制台上打印 int . 现在你评论第一个
test()
方法,看看输出的是什么 .这是原始数据类型中的首选hirarchey . 现在来到派生类型会像这样声明一个类
FooChild
并在
Foo
中创建两个新方法然后在main方法中尝试像
testChild(new FooChild());
一样调用testChild
.getWorkDetail(this)不知道子类是什么 . 改为调用getWorkDetail .