Полиморфизм Java - конкретный пример - PullRequest
3 голосов
/ 23 февраля 2011

У меня есть некоторые проблемы со следующим примером (точнее, с одной конкретной строкой). Вот код (вопрос следует после):

public class Up
{
    public void cc(Up u) {System.out.println("A");}
    public void cc(Middle m) {System.out.println("B");}
}

public class Middle extends Up
{
    public void cc(Up u) {System.out.println("C");}
    public void cc(Down d) {System.out.println("D");}
}

public class Down extends Middle
{
    public void cc(Up u) {System.out.println("E");}
    public void cc(Middle m) {System.out.println("F");}
}

public class Test
{
    public static void main(String... args)
    {
        Up uu = new Up();
        Up pp = new Middle();
        Down dd = new Down();

        uu.cc(pp); // "A"
        uu.cc(dd); // "B"
        pp.cc(pp); // "C"
        pp.cc(dd); // "B"
        dd.cc(pp); // "E"
        dd.cc(dd); // "D"
    }
}

Теперь uu.cc(pp); и uu.cc(dd); довольно очевидны, потому что uu является экземпляром Up, а pp "выглядит как" Up также (во время компиляции). Наиболее подходящим методом для dd является cc(Middle m), поскольку dd является экземпляром Down, который наследуется от Middle.

Линии, с которыми у меня больше всего проблем, это pp.cc(dd); и dd.cc(dd). Я действительно немного озадачен тем, какой метод выбран, когда и как эти вещи определяются при компиляции или во время выполнения. Я был бы рад, если бы кто-то мог помочь мне понять.

Ответы [ 2 ]

5 голосов
/ 23 февраля 2011

По сути, метод signature выбирается во время компиляции на основе типов времени компиляции задействованных выражений, а реализация выбирается во время выполнения на основе фактическогореализация только target метода.

Таким образом, во время компиляции pp.cc(dd) пытается найти соответствие для Up.cc(Down).Наиболее точное совпадение - Up.cc(Middle), так что именно это заканчивается в скомпилированном коде.Теперь во время выполнения реализация этого будет Up.cc(Middle), потому что Middle не переопределяет сигнатуру этого метода.Следовательно, он печатает «B».

Теперь во время компиляции dd.cc(dd) пытается найти совпадение для Down.cc(Down). Здесь есть два соответствующих варианта - либо Middle.cc(Down), который соответствует параметру точно, или Down.cc(Middle), что точно соответствует типу цели точно.Компилятор предпочитает Middle.cc(Down).Во время выполнения снова этот метод не был переопределен в Down, поэтому он печатает «D».

Соответствующий бит спецификации для разрешения перегрузки равен 15.12, и, в частности, 15.12.2 - определение метода подписи .

0 голосов
/ 23 февраля 2011

В pp.cc(dd); компилятор должен выбирать между методами, относящимися к типу pp, Up. Лучше всего подходит cc(Middle m). Вы не переопределяете этот метод в Middle, поэтому во время выполнения вызывается метод Up.

В dd.cc(dd) компилятор выбирает между методами, принадлежащими Down, Middle или Up, поскольку dd является Down. Middle метод cc(Down) точно соответствует типу dd и выбран.

Итак, во время компиляции выбор делается на основе объявленного типа переменной и наиболее подходящей сигнатуры метода. Затем применяются нормальные правила переопределения.

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