17

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

这里涉及到 Java 中虚拟方法或方法重载/解析的任何特性?任何直接参考 Java 语言规范?哪个术语描述了这种行为?非常感谢。

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);
    }
}
4

2 回答 2

24

JLS 在§8.4.9 重载中声明:

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

所以在你的情况下:

  1. 方法参数 ( this) 是编译时类型Parent,因此print(Parent)调用该方法。
  2. 如果Worker该类是子类并且子类将覆盖该方法,并且worker实例属于该子类,则将调用被覆盖的方法。

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

于 2010-05-08T13:25:01.887 回答
5

原因是在doJob中实现Parent而不是在中重载Child。它传递this给工作人员的print方法,因为thisParent该方法Worker::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()inChild等价于Child.class.

于 2010-05-08T13:23:21.847 回答