我在超类中有一个重载方法的基本继承情况。
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
行必须变形为超级类。然而,这不是我发现的。
显然,代码this
中的这一点是Employee
对象,但它仍然选择执行重载方法getWorkDetail(Person p)
。任何人都可以解释这种行为吗?
答案 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.eatenBy
,Meat
和Vegetables
都会实现。这些类将调用更具体的eatMeat
或eatVegetables
方法,该方法使用正确的(动态)类型。
答案 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。