当前位置: 首页 > 知识库问答 >
问题:

继承

孟建木
2023-03-14

有人能解释我这里发生了什么,为什么?

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解释第四种情况,它们只能访问Base2成员变量

共有2个答案

汪正雅
2023-03-14
匿名用户

让我们从一些背景开始。

在继承Java教程中指出:

超类中的私有成员

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

多态性一章中指出:

Java html" target="_blank">虚拟机 (JVM) 为每个变量中引用的对象调用相应的方法。它不调用由变量类型定义的方法。此行为称为虚拟方法调用,演示了 Java 语言中重要多态性功能的一个方面。

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

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

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

现在回到问题本身。

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

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

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

在最后一个例子中,您重写了访问器和赋值器。因此,它们在基2的f上操作。唯一返回f的初始值的调用显然是< code>super.getF()。

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

贡和裕
2023-03-14

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

因为设置了Base的更改值,所以会得到3 2 2 2。f</code>变量,但get方法获取的值为<code>Base2.f</code>变量。

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

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

 类似资料:
  • FAQs in section [24]: [24.1] 如何表示“私有继承”? [24.2] 私有继承和组合(composition)有什么类似? [24.3] 我应该选谁:组合还是私有继承? [24.4] 从私有继承类到父类需要指针类型转换吗? [24.5] 保护继承和私有继承的关系是什么? [24.6] 私有继承和保护继承的访问规则是什么? 24.1 如何表示“私有继承”? 用 : priv

  • 问题内容: 假设Java具有以下层次结构类: 这是C#中相同代码的(盲)重复: 当我执行Java代码时,我得到了C#返回的信息。 对我来说,C#的结果更有意义,因为引用B调用了它自己的方法。 Java设计者决定打印而不是打印的逻辑是什么?我的意思是,为什么引用B在C中使用覆盖方法?这种方法的优势是什么? 如何更改Java代码以像C#一样打印出来?我的意思是,我怎么教Java调用它使用的完全引用的方

  • 一个类可以从另一个类继承方法、属性和其他的特性。当一个类从另一个类继承的时候,继承的类就是所谓的子类,而这个类继承的类被称为父类。在 Swift 中,继承与其他类型不同的基础分类行为。 在 Swift 中类可以调用和访问属于它们父类的方法、属性和下标脚本,并且可以提供它们自己重写的方法,属性和下标脚本来定义或修改它们的行为。Swift 会通过检查重写定义都有一个与之匹配的父类定义来确保你的重写是正

  • 本页包含内容: 定义一个基类(Base class) 子类生成(Subclassing) 重写(Overriding) 防止重写 一个类可以继承(inherit)另一个类的方法(methods),属性(property)和其它特性。当一个类继承其它类时,继承类叫子类(subclass),被继承类叫超类(或父类,superclass)。在 Swift 中,继承是区分「类」与其它类型的一个基本特征。

  • 构造函数的继承 __proto__属性 属性的继承 对象的原生属性 对象的继承属性 获取所有属性 对象的拷贝 参考链接 构造函数的继承 JavaScript通过构造函数生成实例对象,所以要实现对象的继承,就是要实现构造函数的继承。 假定有一个Shape构造函数。 function Shape() { this.x = 0; this.y = 0; } Shape.prototype.mo

  • 目标 了解类分层结构的概念 了解实现构造方法的各种方式 了解何时和为什么使用抽象类和方法 了解如何将一个引用从一个类赋给一个类型属于另一个类的变量。 继承的工作原理 Java 代码中的类存在于分层结构中。分层结构中的给定类上方的类是该类的超类。这个特定的类是分层结构中每个更高层的类的子类。子类继承它的超类。java.lang.Object 类位于类分层结构的顶部 — 所以每个 Java 类是 Ob