我在超类中有一个重载方法的基本继承情况。
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
对象(静态和动态类型)并调用。工作()
:
public static void main(String[] args){
Employee e1 = new Employee("Manager1", 1976, "Female");
e1.work();
}
最后打印出来
此人不是员工
看了这个,我想既然对象的静态和动态类型都是e1
,它会调用Person中的重载方法,该方法将雇员
作为参数。由于我显然错了,我打开了一个调试器,假设Person
类中的getWorkDetail(this)行中对“this”的引用一定已经变成了它的超级类。然而,这不是我发现的。
显然,在代码中的这一点上,这个
是一个雇员
对象,但是它仍然选择执行重载的方法getWorkDetail(Person p)
。有人能解释这种行为吗?
在某些语言中,参数被解析为其动态类型,但在java中则不是。编译器已经在编译时确定您的getWorkDetail(这个)的位置
将被删除
这个
属于Person
类型,因此调用getWorkDetail(Person e)
。在你的具体案例中,解决方案是显而易见的。正如其他人已经指出的,您需要重写Employee
类中的getWorkDetail()
。
要解决在运行时解析参数类型的一般问题,应避免使用
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);
}
}
你可以这样称呼它:
Animal animal = new Shark();
Food someMeat = new Meat();
Food someVegetables= new Vegetables();
animal.eat(someMeat); // prints "Tasty meat!"
animal.eat(someVegetables); // prints "Yuck!"
按照访客模式调用
动物。吃
将调用食物。eatenBy
,它由肉
和蔬菜
实现。这些类将调用更具体的eatMeat
或EatGreens
方法,该方法使用正确的(动态)类型。
重载解析发生在编译时,而不是运行时。
因此,当您调用getWork细节(this)时,this
被假定为Person
(这是静态类型),因此称为相应的重载。
注意:在Employee
类中使用this
将使其成为Employee
类型。您可以通过如下方式在Employee
中重载work()
来验证这一点。
class Employee extends Person {
...
public void work() {
getWorkDetails(this); // This should print "This person is an Employee"
}
}
与方法重写不同,方法重载是基于静态类型链接的。在这种情况下,Person
中的getWorkDetail(this)
只知道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");
}
}
在以下程序中: 输出为“str”,有人能解释一下为什么要打印str吗?我无法理解这一点。
问题内容: 对于以下代码,为什么打印A,B?我希望它能打印B,B。而且,由JVM执行的方法调用是动态还是静态评估? 问题答案: 重载由编译器 静态 确定。 重写 是在执行时完成的,但这不是这里的因素。 的静态类型为A,因此第一个方法调用解析为。
我有一个Foo和Bar对象的列表,以及每个相应对象的转换器。 Convert-method需要有所不同,因为Bar1与Bar2和Bar3等有很大不同,但是我想创建一个方法来处理所有可能的列表。 是否可以创建一个泛型方法,根据列表的内容调用相应的非泛型方法? 到目前为止,我已经尝试过了: 但这并不能编译,因为"无法解析方法'Converts(T, S)'" 有什么想法吗?
问题内容: 根据Java Doc 该接口定义了一个单一方法,旨在包含在线程中执行的代码。将Runnable对象传递给Thread构造函数。 因此, 当我们执行HelloRunnable时,谁调用了内部run方法? 在类中,方法如下所示: 从这段代码中,我们可以看到start方法没有调用该方法。 问题答案: 在以下文档中正确声明: Java虚拟机调用此线程的方法 因此,正是JVM中的本机代码负责调用
问题内容: 谁能详细解释在我的测试代码段中使用实例时重载方法被调用的原因? 这里涉及虚拟方法或Java中方法重载/解析的特殊性吗?是否直接引用Java Lang Spec?哪个术语描述了这种行为?非常感谢。 问题答案: JLS在§8.4.9重载中规定: 调用方法时(第15.12节),实际参数(和任何显式类型参数)的数量以及参数的 编译时类型 在编译时用于确定将要调用的方法的签名( §15.12.2
首先,我不知道如何得体地表达这个问题,所以这是我的建议。 假设我们有以下重载方法: 离开这张桌子,我又问了一个问题 以下是我在当地得到的结果: 编译器如何知道调用哪个方法?例如,它如何区分什么是和什么是?