【问题标题】:How Does the JVM handle Dynamic Dispatch in this Situation?JVM 在这种情况下如何处理动态调度?
【发布时间】:2013-05-22 22:35:30
【问题描述】:

给定以下来源和输出:

来源:

public class A
{
  public void foo()
  {
    bar();
  }

  public void bar()
  {
    System.out.println ("in A's bar() method");
  }
}

public class B extends A
{
  @Override
  public void foo()
  {
    super.foo();

    // Do some specialized B stuff
  }

  @Override
  public void bar()
  {
    System.out.println ("in B's bar() method");
  }
}

public class Main
{
  public static void main (String... args)
  {
    B b = new B();

    b.foo();
  }
}

输出:

in B's bar() method

有人可以向我解释一下 JVM 如何足够聪明地在这种情况下多态地调用 B(而不是 A)的 bar() 方法吗?我想知道这里幕后发生了什么样的动态调度魔法。

更新:如果我不够清楚,我基本上知道发生了什么,我正在寻找有关 JVM 如何使其在幕后发生的具体细节。到目前为止的答案太简单了。

更新 2:也许我不够清楚。当b.foo() 被调用时,然后super.foo() 被调用,然后bar() 在类A 的foo() 中被调用。既然super 关键字显式指定了A 类,那么在专门调用super.foo() 时调用的bar() 不调用类A 的bar() 方法怎么办? JVM 需要经过哪些步骤才能解决这个问题?

另外,这是否意味着从他们自己的类中调用公共方法通常是个坏主意,因为它们可以以这种方式被覆盖?

【问题讨论】:

  • 如果您有解决方案,请分享。我也在寻找这个问题的解决方案。 “到底发生了什么”

标签: java jvm polymorphism overriding dispatch


【解决方案1】:

Java 在调用方法时使用对象的类型。

A b = new B();
b.foo();

假设您使用了上面的代码。 在这里,您将创建一个 B 类型的对象并将其分配给 A 类型的引用。由于对象类型是 B,您将调用 B 类中的方法。

【讨论】:

  • 我知道你描述的场景,但这不是我要问的。不过感谢您的回答。
【解决方案2】:

即使您当前所在的构造函数或方法是在超类中定义的,对象也不会更改类型。它仍然是B 类型的对象。这可以通过使用this 关键字来证明。

this 指的是当前对象。这与定义当前方法或构造函数的类不同。

尝试在A 的构造函数或foo() 方法中输入以下内容:

System.out.println(this.getClass());

【讨论】:

  • 我照你说的做了;它既有趣又有帮助,但我仍在寻找更多关于幕后发生的事情的细节。
【解决方案3】:

函数调用顺序是(从eclipse调试视图):

1. B.foo()      // super.foo()
2. B(A).foo()   // bar()
3. B.bar()

线程调用 super.foo() 后,JVM 会检查 B 中是否有任何实现(因为我们仍然在堆栈中持有 B.class),如果有,则 JVM 会调用它。

此功能由 JVM 实现保证。它不是智能,只是这样设计的,就像 C++ 的 virtual 方法一样。

希望对你有帮助。

【讨论】:

  • 感谢您的解释。如果您更详细地了解如何 JVM 检查 B 中的实现,并了解 JVM 在该程序的每个方法调用中采取的步骤,我会接受您的回答。请查看我的更新。
猜你喜欢
  • 2014-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-12
  • 2021-08-01
相关资源
最近更新 更多