Java方法重载+双重调度
任何人都可以详细解释在我的测试代码段中使用Child
实例时调用重载方法print(Parent parent)
的原因吗?
这里涉及Java中的任何虚拟方法或方法重载/解析的特征? 有没有直接引用Java Lang Spec? 哪个术语描述了这种行为? 非常感谢。
public class InheritancePlay { public static class Parent { public void doJob(Worker worker) { System.out.println("this is " + this.getClass().getName()); worker.print(this); } } public static class Child extends Parent { } public static class Worker { public void print(Parent parent) { System.out.println("Why this method resolution happens?"); } public void print(Child child) { System.out.println("This is not called"); } } public static void main(String[] args) { Child child = new Child(); Worker worker = new Worker(); child.doJob(worker); } }
JLS声明在§8.4.9中重载 :
- 调用方法时(第15.12节),在编译时使用实际参数的数量(以及任何显式类型参数)和参数的编译时类型来确定将被调用的方法的签名( §15.12.2)。
- 如果要调用的方法是实例方法,则将在运行时使用动态方法查找(第15.12.4节)确定要调用的实际方法。
所以在你的情况下:
- 方法参数(
this
)是编译时类型Parent
,因此调用方法print(Parent)
。 - 如果
Worker
类是子类,并且子类将覆盖该方法,并且worker
实例属于该子类,则将调用重写的方法。
Java中不存在双重调度。 您必须模拟它,例如使用访客模式 。 在这种模式中,基本上,每个子类实现一个accept
方法并使用this
作为参数调用visitor,并且this
具有子类的编译时类型,因此使用了所需的方法重载。
原因是doJob
在Parent
实现,而不是在Child
重载。 它this
传递给worker的print
方法,因为this
是Parent
类型,将调用方法Worker::print(Parent)
。
为了让Worker::print(Parent)
调用,你需要在Child
重载doJob
:
public static class Child extends Parent { public void doJob(Worker worker) { System.out.println("from Child: this is " + this.getClass().getName()); worker.print(this); } }
在上面的代码中, Child
中的Child.class
this.getClass()
等同于Child.class
。