此代碼:爲什麼這種Java方法通過聲明類型而不是運行時類型進行變形?
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()
的調用是特別令人困惑,因爲task
被聲明爲Action
在這一點上。
如果它的確與衆不同,這就是Java 6:
$ 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)
我可以改變我的代碼,使其工作,但我想明白爲什麼這是行不通的。謝謝您的幫助!
+1:這是正確的答案。總之,Java不會執行* double dispatch *(儘管它可以被仿真)。 –
因此,調度是基於聲明的參數類型,而不是運行時參數類型?我想我可以理解實際的規則,但我不明白爲什麼會這樣實施。看起來它只是稍微遲了一點。 –
好吧,看起來厄內斯特回答我的後續爲什麼 - 謝謝! –