Почему этот метод Java является полиморфированием по объявлению типа, а не типа выполнения?

StackOverflow https://stackoverflow.com/questions/5331620

  •  26-10-2019
  •  | 
  •  

Вопрос

Этот код:

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)

Я могу изменить свой код, чтобы заставить его работать, но я хотел бы понять, почему он не работает. Спасибо за помощь!

Это было полезно?

Решение

Так работает диспетчер.

Рассылка сначала основана на типах статических параметров, и после выбора статической сигнатуры, тогда тип времени выполнения объекта, содержащего метод, используется для выяснения, какое переопределение используется.

Например, в

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

Другие советы

Выбор между перегруженными методами всегда производится во время компиляции, никогда не во время выполнения. Полиморфизм времени выполнения включает в себя выбор между методами, которые переопределяют другие методы - т.е. методы с идентичными подписями.

Потому что, как только вы пройдете Server в foo или же bar, в объеме этого звонка, это не Server но скорее а Runner.

Поэтому, когда вы бежите delegate Это будет связываться с наиболее подходящим совпадением в соответствии с подписью метода. delegate(Runner) не требует опасного подавления параметра Scoped в Server.

Обратите внимание, что эта область не выполнена во время выполнения, она также будет придерживаться статического анализа исходного кода. Просто вы помните, что сервер был Server Это смущает вас. Если вы проанализируете код без этого дополнительного знания. delegate(Runner) Действительно вы только действительный выбор.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top