Java 虚方法调用
Java virtual method invocation
假设我有以下代码:
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?
书上说"you get the behavior associated with the object to which the variable refers at runtime"。好的,当调用 方法 getDetails
时,我得到管理器 class 的行为,但是当我访问属性 salary
时,我得到变量的行为而不是对象。这是为什么?
没有字段的多态性。 sub-class中的字段隐藏了super-class中的同名字段,但是如果你使用super-class类型的变量-Employee
- 访问字段,你得到超class.
的字段
我看不出在 super-class 和 sub-class 中声明具有相同名称的字段有什么意义。如果 sub-class 可以访问 super-class 的字段,则不应声明同名字段。
如果必须在super-class和sub-class中声明一个同名字段,可以通过getter和[=访问该字段实现多态33=] 方法。您可以覆盖子class中的getter和setter方法,以便它们访问子class的字段而不是超class的字段=18=].
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
class 是 parent
class 并且调用的属性将 return 父属性的值(因为它们具有相同的名称和类型)。
因为这不是 Virtual Method Invocation
。
引述:
you get the behavior associated with the object to which the variable refers at runtime
您忽略了变量 salary
不是行为的一部分 - 它是对象的状态。
此行为是由于隐藏字段。
If the class declares a field with a certain name, then the declaration of that field is said to hide any and all accessible declarations of fields with the same name in superclasses, and superinterfaces of the class.
In this respect, hiding of fields differs from hiding of methods (§8.4.8.3), for there is no distinction drawn between static and non-static fields in field hiding whereas a distinction is drawn between static and non-static methods in method hiding.
A hidden field can be accessed by using a qualified name (§6.5.6.2) if it is static, or by using a field access expression that contains the keyword super (§15.11.2) or a cast to a superclass type.
因此在您的情况下,您通过使用 Employee
class 的引用变量直接访问隐藏变量 salary
来存储 Manager
的对象(转换为超级class 类型).
所以它会打印 Employee
hidden salary
而不是 Employee
class salary
.
假设我有以下代码:
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?
书上说"you get the behavior associated with the object to which the variable refers at runtime"。好的,当调用 方法 getDetails
时,我得到管理器 class 的行为,但是当我访问属性 salary
时,我得到变量的行为而不是对象。这是为什么?
没有字段的多态性。 sub-class中的字段隐藏了super-class中的同名字段,但是如果你使用super-class类型的变量-Employee
- 访问字段,你得到超class.
我看不出在 super-class 和 sub-class 中声明具有相同名称的字段有什么意义。如果 sub-class 可以访问 super-class 的字段,则不应声明同名字段。
如果必须在super-class和sub-class中声明一个同名字段,可以通过getter和[=访问该字段实现多态33=] 方法。您可以覆盖子class中的getter和setter方法,以便它们访问子class的字段而不是超class的字段=18=].
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
class 是 parent
class 并且调用的属性将 return 父属性的值(因为它们具有相同的名称和类型)。
因为这不是 Virtual Method Invocation
。
引述:
you get the behavior associated with the object to which the variable refers at runtime
您忽略了变量 salary
不是行为的一部分 - 它是对象的状态。
此行为是由于隐藏字段。
If the class declares a field with a certain name, then the declaration of that field is said to hide any and all accessible declarations of fields with the same name in superclasses, and superinterfaces of the class.
In this respect, hiding of fields differs from hiding of methods (§8.4.8.3), for there is no distinction drawn between static and non-static fields in field hiding whereas a distinction is drawn between static and non-static methods in method hiding.
A hidden field can be accessed by using a qualified name (§6.5.6.2) if it is static, or by using a field access expression that contains the keyword super (§15.11.2) or a cast to a superclass type.
因此在您的情况下,您通过使用 Employee
class 的引用变量直接访问隐藏变量 salary
来存储 Manager
的对象(转换为超级class 类型).
所以它会打印 Employee
hidden salary
而不是 Employee
class salary
.