当前位置: 首页 > 面试题库 >

用继承和重写方法使Java的输出混乱

徐晔
2023-03-14
问题内容

我偶然发现了这段代码。
我试图在实际运行之前猜测运行它的结果。看到他们时,我真的很困惑,需要一些解释。
这是代码:

public class A {
    String bar = "A.bar";
    A() { foo(); }

    public void foo() {
        System.out.println("A.foo(): bar = " + bar);
    }
}

public class B extends A {
    String bar = "B.bar";
    B() { foo(); }
    public void foo() {
        System.out.println("B.foo(): bar = " + bar);
    }
}

public class C {
    public static void main(String[] args) {
        A a = new B();
        System.out.println("a.bar = " + a.bar);
        a.foo();
    }
}

输出为:

B.foo(): bar = null
B.foo(): bar = B.bar
a.bar = A.bar
B.foo(): bar = B.bar

这是为什么?

  • 怎么bar = null
  • 为什么会a.bar = A.bar出现?我还没有实例化A
  • 如果A出现,为什么 之后 B呢?

问题答案:

在我开始解释代码执行的每一步之前,您应该了解一些事实:

  • 根据引用类型解析字段引用,并在运行时基于对象类型解析方法调用(以动态方式)。
  • super()即使您自己没有将其 隐式 放置在 每个 构造函数中(如果您调用它也不会被调用super(int x, int y))。
  • 从构造函数中调用“可重写的”方法被认为是非常不好的做法-您将了解为什么执行此过程。

现在,让我们逐步分解代码:

  • 您可以B通过调用其默认构造函数实例化B()
  • 就像我之前说过的那样,对的调用super()隐式 添加到任何构造函数中,因此A()立即被调用。
  • 在内部A()调用foo(),在类中覆盖了B这就是为什么foo()从调用B
  • Bs 内部,foo()您将获得输出,B.foo(): bar = null因为Java B尚未初始化的字段(尚未执行其构造函数!),并且null默认将对象类型的字段初始化为。
  • 现在,我们已经完成了的构造函数,A()回到的构造函数B()
  • 里面说的构造函数,我们必须调用foo()一次,而这又是Bfoo()。但是与上次不同的是,正确地B初始化了它的字段(在调用之后super()),以便您获得期望的B.foo(): bar = B.bar
  • 现在我们回到了热情的拥抱main
  • 您访问a.bar,并因为正如我所说的字段引用是基于引用类型解决,你得到的场barA
  • 最后,出于相同的原因,您调用a.foo()再次触发Bfoo(),该再次打印b.bar

我们完成了!:)

进一步的参考和有价值的阅读材料:
静态和动态绑定说明
构造函数调用的顺序



 类似资料:
  • 我偶然发现了这段代码。 在实际运行它之前,我试图猜测运行它的结果是什么。当我看到它们时,我真的很困惑&需要一些解释。 这是代码: 为什么会这样? ? 为什么还要出现?我根本没有实例化。 并且如果出现,为什么会出现在之后?

  • “编写一个名为clsWorker的超类和子类clsHourlyWorker和clssalariedworker。每个工人都有一个名字和一个工资率。编写计算每个员工周薪的方法computePay(int hours)。小时工按实际工作小时数获得小时工资,如果小时数最多为40小时。如果小时工工作超过40小时,则按时间半支付超出部分。受薪工人得到40小时的小时工资,无论实际小时数是多少。为继承编写一个测

  • 如何/可以重写来自非继承类的方法?其次,有没有比“非继承类”更好的术语? 我有一个“扩展”JFrame的类,需要从JPanel重写paintComponent。怎么做?或者它可以扩展JPanel,并需要访问方法,如setTitle()、setResizable()和setDefaultCloseOperation();

  • 问题内容: 我有两个课,和。它们看起来像这样: 此错误指向Field的: 我希望首先调用Background init ()。要将“ a,b”传递给Fields的 init (),Field会分配a和b,然后将其中包含三个0的列表分配给field。然后让Background的 init ()继续,然后调用它自己的buildField()并用包含c的列表覆盖self.field。 似乎我还没有完全理

  • 问题内容: 这是我遇到的一个测试练习问题,希望您能帮助我理解概念 让Hawk成为Bird的子类。假设某个类有两个重载的方法void foo(Hawk h)和void foo(Bird b)。在声明Bird x = new Hawk()之后,将在调用foo(x)中执行哪个版本; 这是我到目前为止的代码,有人可以向我解释为什么foo(bird b)被执行吗? 问题答案: Java执行重载解析以选择方法

  • 我创建了一个(个人、学生、员工、教职员工)类。Person必须将Student和Employee分为子类。Employee有两个子类:教员和职员。我已经完成了所有的编码,他们工作得很好,除了我的驱动程序类TestPerson程序给出了编译错误 注:一个测试程序,创建一个人、学生、员工、教职员工,并调用他们的toString方法。 驱动程序类TestPerson的错误。以下是java:- **我只是