继承和动态绑定



谁能解释一下这里发生了什么以及为什么?

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

如果我用getter取消第1行注释,输出将是 3,2,2

如果我用setter取消第2行注释,输出将是1 1,1,1

如果我取消第1行和第2行(带有setter和getter)的注释,输出将是 1,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

如果用子类中的代码重写父类中的方法,则该重写方法不能访问私有成员变量,即使父类中被重写的方法可以访问。子类中的重写方法可以调用父类中的重写方法。

所以,这是解释情况#4的getter和setter,只能访问Base2成员变量

你得到3 3 3 3,因为set/get方法修改了Base.f变量:

你得到3 2 2 2是因为设置了Base.f变量的变化值,但是get方法得到了Base2.f变量的值。

你得到1 1 1 1是因为set方法改变了Base2.f变量的值,但是get方法得到了Base.f变量的值。

你得到1 3 3 3,因为super.getF()返回Base.f变量的值,但其他get方法返回Base2.f变量的值。还有Base2.f变量的set方法更改值

让我们从一些背景开始。

在继承Java教程中说明:

超类中的私有成员

子类不继承父类的私有成员。但是,如果超类有public或protected方法访问它的私有字段,这些字段也可以被子类使用。

在多态性一章中说明:

Java虚拟机(JVM)调用适当的方法在每个变量中引用的对象。它不调用方法,该方法由变量类型定义。这种行为是称为虚拟方法调用并演示一个方面Java语言中重要的多态性特性

最后,在同一教程的隐藏字段章节中说明:

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

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

现在回到问题本身。

在您的第一个示例中,您既没有重写访问器也没有重写mutator—您只是一直调用继承的那一个。它们返回并修改Base的f的值。为什么继承的accessor/mutator不返回/修改Base2f的值?因为即使Basef不是私有的,它也不会被覆盖,而只是被隐藏。

在第二个示例中,您重写了访问器。这是开始涉及多态性的地方。这个简短的回答可能有助于理解它。调用b.setF(3)时,设置Base的f的值。但是,当您调用getF()时,您将获得Base2f的值,除非您使用关键字super调用它。请注意,在上次调用中,System.out.println(((Base)b).getF())转换为Base没有任何作用,因为b已经声明为Base。如果不使用super,就不能调用父类的重写方法(正如您已经知道的,只有实例方法可以被重写)。

在第三个示例中,重写了该mutator。情况与你的第二个例子相反。调用b.setF(3)时,设置Base2的f的值。但是你总是从getter中得到f (Base),因为getter没有被重写。因此,对getF()的所有4次调用都返回Basef的初始值。

在上一个示例中,重写了访问器和mutator。因此,它们对Base2的f进行操作。唯一返回Basef的初始值的调用显然是super.getF()

这肯定不是一个完美的解释,但我希望它能帮助。

相关内容

  • 没有找到相关文章

最新更新