鉴于以下来源和输出:
来源:
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()
,然后在A类bar()
中调用foo()
。在专门调用bar()
时调用的super.foo()
如何不调用类A的bar()
方法,因为super
关键字明确指定了类A? JVM需要采取哪些步骤来解决这个问题?
另外,这是否意味着从一般情况下调用公共方法是一个坏主意,因为它们可以通过这种方式被覆盖?
答案 0 :(得分:3)
Java在调用方法时使用对象的类型。
A b = new B();
b.foo();
假设你使用了上面的代码。 在这里,您将创建一个B类型的对象,并将其分配给类型为A的引用。由于对象类型为B,您将调用B类中的方法。
答案 1 :(得分:1)
即使您当前所在的构造函数或方法是在超类中定义的,该对象也不会更改类型。它仍然是B
类型的对象。这可以通过使用this
关键字来证明。
this
指的是当前对象。这与定义当前方法或构造函数的类不同。
尝试在A
的构造函数或foo()
方法中输入以下内容:
System.out.println(this.getClass());
答案 2 :(得分:1)
函数调用序列是(来自eclipse调试视图):
1. B.foo() // super.foo()
2. B(A).foo() // bar()
3. B.bar()
在线程调用super.foo()之后,JVM将检查B中是否有任何实现(因为我们仍然在堆栈中保存B.class),如果存在,JVM将调用它。
JVM实现保证了此功能。它不是智能,它只是以这种方式设计,就像C ++的虚拟方法一样。
希望它有所帮助。