【问题标题】:Java virtual method invocationJava 虚拟方法调用
【发布时间】:2015-05-21 07:39:22
【问题描述】:

假设我有以下代码:

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?

这本书说“你会得到与变量在运行时引用的对象相关的行为”。好的,当调用 method getDetails 时,我得到了 Manager 类的行为,但是当我访问属性 salary 时,我得到的是变量而不是对象的行为。这是为什么呢?

【问题讨论】:

    标签: java polymorphism


    【解决方案1】:

    没有字段的多态性。子类中的字段隐藏了超类中同名的字段,但是如果使用超类类型的变量——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
    

    【讨论】:

      【解决方案2】:

      这种行为是由于隐藏字段

      来自JLS 8.3. Field Declarations

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

      在这方面,字段隐藏与方法隐藏不同(第 8.4.8.3 节),因为在字段隐藏中静态和非静态字段之间没有区别,而静态和非静态方法之间存在区别在方法隐藏中。

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

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

      所以它会打印Employee hidden salary 而不是Employeeclass salary

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

          因为这不是Virtual Method Invocation

          如引用:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-02-01
            • 2012-06-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-18
            • 1970-01-01
            相关资源
            最近更新 更多