Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java方法重载+;双重派遣_Java_Oop_Overloading_Double Dispatch - Fatal编程技术网

Java方法重载+;双重派遣

Java方法重载+;双重派遣,java,oop,overloading,double-dispatch,Java,Oop,Overloading,Double Dispatch,有人能详细解释在我的测试代码中使用Child实例时调用重载方法print(Parent-Parent)的原因吗 这里涉及到Java中虚拟方法或方法重载/解析的特殊性吗? 有没有直接引用Java语言规范? 哪个术语描述这种行为? 非常感谢 public class InheritancePlay { public static class Parent { public void doJob(Worker worker) { Sys

有人能详细解释在我的测试代码中使用
Child
实例时调用重载方法
print(Parent-Parent)
的原因吗

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

原因是
doJob
Parent
中实现,而不是在
Child
中重载。它将
this
传递给工作者的
print
方法,因为
this
属于
Parent
类型,将调用方法
worker::print(Parent)

要调用
Worker::print(Parent)
,您需要在
子项中重载
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
中的这个.getClass()
相当于
Child.class

中的JLS状态:

  • 调用方法(§15.12)时,在编译时使用实际参数(以及任何显式类型参数)的数量和参数的编译时类型来确定将调用的方法的签名(§15.12.2)
  • 如果要调用的方法是实例方法,则将在运行时使用动态方法查找(§15.12.4)确定要调用的实际方法
  • 因此,在你的情况下:

  • 方法参数(
    this
    )属于编译时类型
    Parent
    ,因此调用方法
    print(Parent)
  • 如果
    Worker
    类是子类,子类将重写该方法,并且
    Worker
    实例是该子类的实例,则将调用被重写的方法

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

    rsp,感谢您指出这一点,但我知道在Child中重写doJob会使prog工作。问题是我不明白为什么:)。让我们看一下最初的代码。当我们将子对象传递给Parent.doJob时,Parent.doJob中的Java反射证明我们处理的是这种类型的Child,那么为什么重载方法的解析会失败呢?@Max,在方法中,
    this
    的类型始终是方法所在的类的类型。编译器无法知道该类将来将被继承,它必须使用它当时拥有的知识
    this.getClass()
    是运行时信息,而不是编译时信息。Christian,谢谢你详尽的回答!所以我们在这里讨论运行时和编译时类型的问题。我将深入探讨这个话题。(这里提到双重分派是因为我在学习访问者模式时遇到了这个问题:))。马克斯