说我有以下代码:
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
时,我得到变量而不是对象的行为。那是为什么?
答案 0 :(得分:6)
没有字段的多态性。子类中的字段隐藏了超类中具有相同名称的字段,但如果使用超类类型的变量 - Employee
- 来访问该字段,则会获得该字段的字段超类。
我没有看到在超类和子类中声明具有相同名称的字段的重点。如果子类可以访问超类的字段,它就不应该声明一个同名的字段。
如果必须在超类和子类中声明一个同名字段,则可以通过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
答案 1 :(得分:2)
此行为是因为 隐藏字段 。
如果类声明了一个具有特定名称的字段,那么该字段的声明将被隐藏为隐藏超类中具有相同名称的字段的任何和所有可访问声明,以及该类的超接口。
在这方面,隐藏字段不同于隐藏方法(第8.4.8.3节),因为在字段隐藏中静态和非静态字段之间没有区别,而静态和非静态方法之间存在区别方法隐藏。
如果隐藏字段是静态的,或者使用包含关键字super(§15.11.2)或强制转换的字段访问表达式,则可以使用限定名称(第6.5.6.2节)访问隐藏字段超类型。
因此,在您的情况下,您通过使用salary
类的引用变量直接访问隐藏变量Employee
来存储Manager
的对象(强制转换为超类类型)。
因此,它会打印Employee
隐藏salary
而不是Employee
类salary
。
答案 2 :(得分:0)
Employee
类是parent
类,被调用的属性将返回父属性的值(因为它们具有相同的名称和类型)。
答案 3 :(得分:0)
因为这不是Virtual Method Invocation
。
引用:
您将获得与变量在运行时引用的对象关联的行为
你忽略了变量salary
不是行为的一部分 - 它是对象的状态。