java - 为什么这个 Java 方法通过声明的类型而不是运行时类型进行多态化?

标签 java polymorphism late-binding

这段代码:

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

我可以非常清楚地看到,Task 的方法比 Action 的方法被选择。不过,我不明白为什么,因为对象总是知道它们是什么,而且我认为 Java 的后期绑定(bind)方法选择能够区分方法签名的差异。对 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)

我可以更改我的代码使其工作,但我想了解为什么它不起作用。感谢您的帮助!

最佳答案

这就是 java 中的调度工作方式。

Dispatch 首先基于静态参数类型,一旦选择了静态签名,就会使用包含该方法的对象的运行时类型来确定使用哪个覆盖。

例如,在

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).

关于java - 为什么这个 Java 方法通过声明的类型而不是运行时类型进行多态化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5331620/

相关文章:

java - 在 Pebble 模板中插入位于文件系统中任意位置的模板

php - 拉拉维尔 5.4 : search by tag

c - Gambit-C 方案 : cannot load a windows dll

PHPDoc 和后期(静态或动态)绑定(bind)

java - 从运行的 C++ 代码调用运行的 Java 代码,反之亦然

java - 枚举声明调用方法

Java:使用引用游标作为 OUT 调用存储过程时结果集为空

C# 如何访问已实现的接口(interface)中不存在的对象属性

c++ - 虚函数 C++

ios - 在运行时在 Objective-C 中检测和使用可选的外部 C 库