Java虚拟方法调用

Java虚拟方法调用,java,polymorphism,Java,Polymorphism,假设我有以下代码: public class Employee { public int salary = 2000; public void getDetails() {...} } public class Manager extends Employee { public int salary = 5000; public int allowance = 8000; public void getDetails() {...} } 以及执行以下操

假设我有以下代码:

public class Employee
{
    public int salary = 2000;
    public void getDetails() {...}
}

public class Manager extends Employee
{
    public int salary = 5000;
    public int allowance = 8000;
    public void getDetails() {...}
}
以及执行以下操作的
main()

Employee emp = new Employee();
Manager man = new Manager();
emp.getDetails(); // method of Employee called, output ok.
man.getDetails(); // method of Manager called, output ok.

Employee emp_new = new Manager();
emp_new.getDetails(); // method of Manager called, ok.
System.out.println(emp_new.allowance); // problem, as Employee doesn't know about allowance. Ok

// the problem
System.out.println(emp_new.salary); // why 2000 and not 5000?

这本书说“您可以在运行时获得与变量引用的对象相关联的行为”。好的,当调用方法
getDetails
时,我得到Manager类的行为,但是当我访问属性
salary
时,我得到的是变量的行为,而不是对象的行为。为什么会这样?

字段没有多态性。子类中的字段隐藏了超类中具有相同名称的字段,但如果使用超类类型的变量-
Employee
-访问该字段,则会得到该超类的字段

public class Employee
{
    private int salary = 2000;
    public void getSalary() {
        return salary;
    }
}

public class Manager extends Employee
{
    private int salary = 5000;
    @Override
    public void getSalary () {
        return salary;
    }
}

...

Employee emp_new = new Manager();
System.out.println(emp_new.getSalary()); // will print 5000
我不认为在超类和子类中声明具有相同名称的字段有什么意义。如果子类可以访问超类的字段,则不应声明同名字段

如果必须在超类和子类中声明同名的字段,则可以通过getter和setter方法访问字段来实现多态性。您可以重写子类中的getter和setter方法,以便它们访问子类的字段而不是超类的字段

public class Employee
{
    private int salary = 2000;
    public void getSalary() {
        return salary;
    }
}

public class Manager extends Employee
{
    private int salary = 5000;
    @Override
    public void getSalary () {
        return salary;
    }
}

...

Employee emp_new = new Manager();
System.out.println(emp_new.getSalary()); // will print 5000

Employee
类是
父类,被调用的属性将返回父属性的值(因为它们具有相同的名称和类型)。

因为这不是
虚拟方法调用

引述如下:

您可以在运行时获得与变量引用的对象关联的行为


您忽略了变量
salary
不是行为的一部分-它是对象的状态。

此行为是因为隐藏了字段

如果类声明了一个具有特定名称的字段,那么该字段的声明将隐藏该类的超类和超接口中具有相同名称的字段的任何和所有可访问声明

在这方面,字段的隐藏不同于方法的隐藏(§8.4.8.3),因为在字段隐藏中静态字段和非静态字段之间没有区别,而在方法隐藏中静态方法和非静态方法之间有区别

如果隐藏字段是静态的,则可以使用限定名称(§6.5.6.2),或者使用包含关键字super(§15.11.2)的字段访问表达式或转换为超类类型来访问该字段。

因此,在您的情况下,通过使用
Employee
类的引用变量来存储
Manager
(转换为超类类型)的对象,您可以直接访问隐藏变量
salary

因此,它将打印
Employee
hidden
salary
而不是
Employee
class
salary