Java 为什么从超类调用时会调用子类中的方法?

Java 为什么从超类调用时会调用子类中的方法?,java,polymorphism,overriding,Java,Polymorphism,Overriding,我的代码如下所示: public abstract class BaseClass{ public void update() { //... } public void somethingHappenedSoCallUpdate() { update(); } } public class ExtendingClass extends BaseClass{ @Override public void update() { //..

我的代码如下所示:

public abstract class BaseClass{
  public void update() {
      //...
  }

  public void somethingHappenedSoCallUpdate() {
      update();
  }
}

public class ExtendingClass extends BaseClass{
  @Override
  public void update() {
      //...
  }
}

有一个
ExtendingClass
的实例,在某个点上调用了方法
somethingHappenedSocalUpdate()
。我希望该方法将调用
BaseClass.update()
,但是调用了
ExtendingClass.update()
。有人能解释一下原因吗?

这是多态性:根据对象的实际类型在运行时调用正确的方法,这是一个动态绑定。

您重写了该方法,因此如果仍希望抽象类中的代码运行,则需要在重写的方法中隐式调用
update()
。所以

public class ExtendingClass extends BaseClass {

  @Override
  public void update() {

      super.update(); // Call the base method.
  }
}
希望有帮助:)


我希望该方法将调用
BaseClass.update()
,但是调用了
ExtendingClass.update()
。有人能解释一下原因吗

因为Java就是这样定义的。默认情况下,所有非私有方法都是虚拟的,这意味着当您重写了方法时,在实例上调用的方法是实例的最重写版本(
ExtendingClass
,在您的情况下),而不考虑方法调用所通过的类型引用。这是现代OOP语言中多态性的基础

编译时类型引用告诉编译器代码是否有权访问该方法;对象的运行时类型告诉JVM要调用的方法的哪个重写

让我们举一个简单的例子:

class Base {
    public void method1() {
        System.out.println("Base#method1");
    }
}
class Derived extends Base {
    @Override
    public void method1() {
        System.out.println("Derived#method1");
    }

    public void method2() {
        System.out.println("Derived#method1");
    }
}

// Usage:
Base b = new Derived();
b.method1(); // Calls Derived#method1, the most-overridden version the
             // actual object has
b.method2(); // Fails to compile; Base doesn't define method2, so the
             // code doesn't have access to call it when using a Base
             // reference, even though the object does have the method

正如@hyde所说,Java方法是虚拟的,这意味着VM在运行时决定调用哪个方法。如果对扩展了
BaseClass
的实例调用
somethingHappenedLocallUpdate()
,则将调用
BaseClass.somethingHappenedLocallUpdate()
,但由于
ExtendingClass
重写了
BaseClass.update()
它将初始化
ExtendingClass.update()
而不是
BaseClass.update()

扩展方法时,您必须这样考虑:
每当你扩展一个方法,把它放在一个堆栈上,当你调用它时,Java就会查看这个“堆栈”并调用最上面的。这意味着,如果您有一个
BaseClass
具有
update()
方法,则可以通过X个类扩展该类,而不是覆盖
update()
方法,但如果X+1类覆盖该方法,Java将始终调用X+1的方法。

因为您在子类中重写了update,并且由于Java方法是虚拟重写的,所以调用了version

选项1 覆盖更新,覆盖发生的某些事情局部更新()方法,并在那里使用
super.update()
而不是
update()

选项2 在超类中将更新设为私有:

private void update() 

在Java中,方法是虚拟的。查找这意味着什么。“我希望该方法将调用BaseClass.update()”-为什么?因为SomethingHappenedSocalUpdate方法仅在基类中定义