Java 方法重载 + 双重调度

2022-09-03 00:50:01

任何人都可以详细解释在我的测试代码中处理实例时调用重载方法的原因吗?print(Parent parent)Child

这里涉及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);
    }
}

答案 1

JLS 在 §8.4.9 重载中指出:

  1. 调用方法时 (§15.12),在编译时将使用实际参数(以及任何显式类型参数)的数量和参数的编译时类型来确定将被调用的方法的签名 (§15.12.2)。
  2. 如果要调用的方法是实例方法,则将在运行时使用动态方法查找 (§15.12.4) 确定要调用的实际方法。

因此,在您的情况下:

  1. 方法参数 () 是编译时类型,因此调用该方法。thisParentprint(Parent)
  2. 如果该类被子类化,并且子类将重写该方法,并且该实例是该子类的,则将调用被覆盖的方法。Workerworker

Java 中不存在双重调度。您必须模拟它,例如通过使用访客模式。在这种模式中,基本上,每个子类实现一个方法,并使用as参数调用访问者,并且具有作为编译时类型的子类,因此使用所需的方法重载。acceptthisthis


答案 2

原因是 在 中实现,而不是在 中重载。它传递给工人的methos,因为该方法的类型将被调用。doJobParentChildthisprintthisParentWorker::print(Parent)

为了调用,您需要在 中重载:Worker::print(Parent)doJobChild

public static class Child extends Parent {
    public void doJob(Worker worker) {
        System.out.println("from Child: this is " + this.getClass().getName());

        worker.print(this);
    }
}

在上面的代码中,等效于 。this.getClass()ChildChild.class