继承与动态绑定

时间:2015-07-24 11:25:22

标签: java inheritance dynamic-binding

有人可以解释一下这里发生了什么以及为什么?

class Base{
    private float f = 1.0f;
    void setF(float f1){ this.f = f1; }
    float getF() {return f;}
    public void xx(){}
}

class Base2 extends Base{
    private float f = 2.0f;

    public void xx(){
        System.out.println(super.getF()+" "+this.getF());
    }

    //float getF() {return f;} //1
    //void setF(float f1){ this.f = f1; } //2

    public static void main(String[]args){
        Base b=new Base2();
        b.setF(3);
        b.xx();
        System.out.println(b.getF());
        System.out.println(((Base)b).getF());
    }
}

此代码的输出将 3 3,3,3

如果我仅使用getter取消注释第1行,则输出 3 2,2,2

如果我只使用setter取消注释第2行,则输出 1 1,1,1

如果我取消注释第1行和第2行(使用setter和getter),输出将 1 3,3,3

        //default output: 3 3, 3, 3
        //with getter: 3 2, 2, 2
        //with setter: 1 1, 1, 1
        //with getter and setter: 1 3, 3, 3

如果使用子类中的代码覆盖父类中的方法,则该覆盖方法无法访问私有成员变量,即使父类中的重写方法也是如此。子类中的重写方法可以调用父类中的重写方法。

因此,它解释了具有getter和setter的情况#4,只能访问Base2成员变量

2 个答案:

答案 0 :(得分:1)

您获得3 3 3 3因为set / get方法修改了Base.f变量:

您获得3 2 2 2因为设置了Base.f变量的更改值,但get方法获得了Base2.f变量的值。

得到1 1 1 1因为设置Base2.f变量的方法更改值,但get方法获取Base.f变量的值。

您获得1 3 3 3因为super.getF()返回Base.f变量的值,但其他get方法返回Base2.f变量的值。此外,set方法更改了Base2.f变量的值。

答案 1 :(得分:1)

让我们从一些背景开始。

Inheritance Java教程中说明:

  

超类中的私人会员

     

子类不继承其父类的私有成员。   但是,如果超类具有公共或受保护的方法   访问其私有字段,子类也可以使用它们。

Polymorphism章节中陈述:

  

Java虚拟机(JVM)为其调用适当的方法   每个变量中引用的对象。它没有打电话给   由变量类型定义的方法。这种行为是   称为虚方法调用并演示了一个方面   Java语言中重要的多态性特征。

最后,在同一教程的Hiding fields章节中说明:

  

在一个类中,一个与该字段中的字段同名的字段   超类隐藏超类的字段,即使它们的类型是   不同。在子类中,超类中的字段不能   由简单名称引用。相反,必须访问该字段   通过超级,这将在下一节中介绍。通常   说来,我们不建议隐藏字段,因为它会使代码变得困难   阅读。

因此,子类无法直接访问超类的私有成员。但是,它们仍然存在,可以使用非私有访问器/ mutator进行访问或修改。

现在回到问题本身。

在你的第一个例子中,你既不覆盖访问者也不覆盖mutator - 你只是一直调用继承的。它们返回并修改 f of Base 的值。 为什么继承的accessor / mutator不返回/修改Base2的 f的值?因为即使 f of Base 不是私有的,也不会被覆盖,只是隐藏。

在第二个示例中,您将覆盖访问者。这是您开始涉及多态性的地方。 This short answer可能有助于理解它。当您致电b.setF(3)时,您需要设置 f of Base 的值。但是,当您致电getF()时,您会获得 f of Base2 的值,除非您使用关键字超级来调用它。 请注意,在您上次通话System.out.println(((Base)b).getF())投射到 基地 时,该功能无效,因为 b 已经声明为 Base 。如果不使用 super ,就不能调用重写的超类方法(正如您所知,只能覆盖实例方法)。

在第三个示例中,您将覆盖mutator。情况与你的第二个例子相反。当您致电b.setF(3)时,您需要设置Base2的 f的值。但是你总是从getter获得 f of Base ,因为getter不会被覆盖。因此,对getF()的所有4次调用都会返回 f of Base 的初始值。

在上一个示例中,您重写了accessor和mutator。因此,它们在Base2的 f 上运行。唯一一个返回 f of Base 的初始值的调用显然是super.getF()

这绝对不是一个完美的解释,但我希望它有所帮助。