3

このコード:

public class PMTest
{

    private static class Runner { }
    private static class Server extends Runner { }

    private static class Task
    {
        public void delegate(Runner runner)
        {
            System.out.println("Task: " + runner.getClass().getName() +
                               " / " + this.getClass().getName());
        }
    }

    private static class Action extends Task
    {
        public void delegate(Server server)
        {
            System.out.println("Action: " + server.getClass().getName() +
                               " / " + this.getClass().getName());
        }
    }


    private static void foo(Task task, Runner runner)
    {
            task.delegate(runner);
    }

    private static void bar(Action task, Runner runner)
    {
            task.delegate(runner);
    }

    private static void baz(Action task, Server runner)
    {
            task.delegate(runner);
    }


    public static void main (String[] args)
    {
        try {
            Server server = new Server();
            Action action = new Action();

            action.delegate(server);
            foo(action, server);
            bar(action, server);
            baz(action, server);

        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

この出力を生成します:

$ java PMTest
Action: PMTest$Server / PMTest$Action
Task: PMTest$Server / PMTest$Action
Task: PMTest$Server / PMTest$Action
Action: PMTest$Server / PMTest$Action

アクションの方法よりもタスクの方法が選択されていることがはっきりとわかります。ただし、オブジェクトは常にオブジェクトが何であるかを知っており、Javaの遅延バインディングメソッドの選択によってメソッドシグネチャの違いを区別できると思ったので、理由はわかりません。その時点でとして宣言されているように、への呼び出しbar()は特に混乱を招きます。taskAction

それが違いを生むなら、これはJava6です。

$ java -version
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
BEA JRockit(R) (build R27.6.5-32_o-121899-1.6.0_14-20091001-2113-linux-ia32, compiled mode)

コードを変更して機能させることはできますが、機能しない理由を理解したいと思います。助けてくれてありがとう!

4

3 に答える 3

5

これが、Javaでのディスパッチの仕組みです。

ディスパッチは、最初に静的パラメータータイプに基づいており、静的シグニチャが選択されると、メソッドを含むオブジェクトの実行時タイプを使用して、どのオーバーライドが使用されているかが判断されます。

たとえば、

void foo(Object o) {
  if (o instanceof Number) { foo((Number) o); }
  else if (o instanceof String) { foo((String) o); }
}

void foo(String s) { ... }

void foo(Number n) { ... }

{ foo((Object) "foo"); }  // Calls foo(Object) which calls foo(String).
{ foo("foo"); }  // Calls foo(String) without first calling foo(Object).
于 2011-03-16T20:55:49.637 に答える
5

オーバーロードされたメソッドの選択は、実行時にではなく、常にコンパイル時に行われます。ランタイムポリモーフィズムには、他のメソッドをオーバーライドするメソッド、つまり同一のシグネチャを持つメソッドから選択することが含まれます。

于 2011-03-16T20:57:12.993 に答える
1

またはServerに渡すと、その呼び出しの範囲では、ではなく、になります。foobarServerRunner

したがって、実行delegateすると、メソッドのシグネチャに従って、最も適切な一致にバインドされます。 delegate(Runner)スコープパラメータの危険なダウンキャストを必要としませんServer

このスコープは実行時に行われないことに注意してください。ソースコードの静的分析にも対応します。Serverサーバーがあなたを混乱させていたことを覚えているだけです。その余分な範囲外の知識なしでコードを分析すると、それがdelegate(Runner)本当にあなただけの有効な選択であることがわかります。

于 2011-03-16T21:02:08.103 に答える