17

私のテストコード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);
    }
}
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には存在しません。たとえば、 Visitor Patternを使用して、それをシミュレートする必要があります。このパターンでは、基本的に、各サブクラスはメソッドを実装し、引数としてacceptビジターを呼び出し、コンパイル時の型としてそのサブクラスを持っているため、目的のメソッドのオーバーロードが使用されます。thisthis

于 2010-05-08T13:25:01.887 に答える
5

その理由は、doJobに実装されてParentおり、でオーバーロードされていないためですChild。メソッドが呼び出されるタイプであるためthis、ワーカーのprintメトスに渡されます。thisParentWorker::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()では、のChildはと同等Child.classです。

于 2010-05-08T13:23:21.847 に答える