3

给定以下源和输出:

资源:

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()。既然关键字明确指定了类A ,bar()那么在专门调用super.foo()不调用类A的bar()方法时如何调用?superJVM 必须经过哪些步骤才能解决这个问题?

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

4

3 回答 3

3

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

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

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

于 2013-05-28T04:46:21.570 回答
1

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

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

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

此功能由 JVM 实现来保证。它并不聪明,它只是这样设计的,就像 C++ 的虚拟方法一样。

希望能帮助到你。

于 2013-05-30T06:24:28.933 回答
1

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

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

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

System.out.println(this.getClass());
于 2013-05-28T05:06:50.563 回答