Я бы начал рисовать картинку ...
Moe - print(Moe)
|
Larry - print(Moe), print(Larry)
|
Curly - print(Moe), print(Larry), print(Curly)
Тогда я бы отслеживал переменные:
- Ларри - stooge1 -> Кудрявый
- Мое - stooge2 -> Ларри
- Мое - stooge3 -> Вьющиеся
- Вьющиеся - stooge4 -> Вьющиеся
Ларри - марионетка5 -> Ларри
stooge1.print(new Moe())
- stooge1 -> Curly, поэтому вызывает Curly.print (Moe)
((Curly)stooge1).print(new Larry());
- stooge1 -> Curly, поэтому вызывает Curly.print (new Larry ())
((Larry)stooge2).print(new Moe());
- stooge2 -> Ларри так называет Larry.print (new Moe ());
stooge2.print(new Curly());
Хорошо, здесь немного сложнее (извините, я остановился здесь раньше)
- stooge2 объявлен Мо. Поэтому, когда компилятор ищет, что вызывать, он вызывает метод print (Moe). Затем во время выполнения он знает, что stooge2 - это Larry, поэтому он вызывает метод Larry.print (Moe).
и т.д ...
Дайте мне знать, что если вам не удастся выполнить весь этот шаг, то все получится.
(обновлено для уточнения следующего)
Итак, общее правило:
- компилятор просматривает тип переменной, чтобы решить, какой метод вызывать.
- среда выполнения смотрит на реальный класс, на который указывает переменная, чтобы решить, откуда взять метод.
Итак, когда у вас есть:
Moe stooge2 = new Larry();
stooge2.print(new Moe());
компилятор говорит:
- можно ли назначить Ларри на stooge2? (да, так как Ларри является подклассом Мо)
- Есть ли у Мо метод печати (Мо)? (Да)
среда выполнения говорит:
- Я должен вызвать метод print (Moe) для этого объекта здесь ... stooge2
- Stooge2 - это точка на Ларри.
- Я вызову метод print (Moe) в классе Larry.
Как только вы все это поработаете, попробуйте избавиться от некоторых методов и посмотрите, как это меняет дело.