Динамическая привязка Java
-
19-08-2019 - |
Вопрос
Я готовлюсь к экзамену и нашел примерную задачу, из-за которой я совершенно растерялся.Для следующего кода найдите, каков результат:
class Moe {
public void print(Moe p) {
System.out.println("Moe 1\n");
}
}
class Larry extends Moe {
public void print(Moe p) {
System.out.println("Larry 1\n");
}
public void print(Larry l) {
System.out.println("Larry 2\n");
}
}
class Curly extends Larry {
public void print(Moe p) {
System.out.println("Curly 1\n");
}
public void print(Larry l) {
System.out.println("Curly 2\n");
}
public void print(Curly b) {
System.out.println("Curly 3\n");
}
}
public class Overloading_Final_Exam {
public static void main (String [] args) {
Larry stooge1 = new Curly();
Moe stooge2 = new Larry();
Moe stooge3 = new Curly();
Curly stooge4 = new Curly();
Larry stooge5 = new Larry();
stooge1.print(new Moe());
((Curly)stooge1).print(new Larry());
((Larry)stooge2).print(new Moe());
stooge2.print(new Curly());
stooge3.print(new Curly());
stooge3.print(new Moe());
stooge3.print(new Larry());
((Curly)stooge3).print(new Larry());
((Curly)stooge3).print(new Curly());
stooge4.print(new Curly());
stooge4.print(new Moe());
stooge4.print(new Larry());
stooge5.print(new Curly());
stooge5.print(new Larry());
stooge5.print(new Moe());
}
}
У меня были свои идеи в голове, но потом, когда я запустил java, я получил нечто совершенно другое:
Curly 1 Curly 2 Larry 1 Larry 1 Curly 1 Curly 1 Curly 1 Curly 2 Curly 3 Curly 3 Curly 1 Curly 2 Larry 2 Larry 2 Larry 1
Первые несколько слов в порядке, но потом я действительно не понимаю.У кого-нибудь есть хорошее объяснение этой проблемы?
Спасибо
Решение
Я бы начал с того, что нарисовал картинку...
Moe - print(Moe)
|
Larry - print(Moe), print(Larry)
|
Curly - print(Moe), print(Larry), print(Curly)
Тогда я бы отслеживал переменные:
- Ларри - марионетка 1 -> Кудрявый
- Мо - марионетка 2 -> Ларри
- Мо - марионетка 3 -> Кудрявый
- Кудрявый - stooge4 -> Кудрявый
Ларри - марионетка 5 -> Ларри
stooge1.print(new Moe())
- stooge1 -> Кудрявый, поэтому вызывает Curly.print(Moe)
((Curly)stooge1).print(new Larry());
- stooge1 -> Curly так называет Curly.print(новый Larry())
((Larry)stooge2).print(new Moe());
- stooge2 -> Ларри так называет Ларри.print(новый Moe());
stooge2.print(new Curly());
Хорошо, здесь все становится немного сложнее (извините, что я остановил один из них раньше здесь)- stooge2 объявлен Мос.Таким образом, когда компилятор ищет, что вызвать, он собирается вызвать метод print(Moe).Затем во время выполнения он знает, что stooge2 - это Larry, поэтому вызывает метод Larry.print(Moe).
и т.д...
Дайте мне знать, если, следуя этому до конца, у вас ничего не получится.
(обновлено, чтобы прояснить следующий)
Итак, общее правило таково:
- компилятор смотрит на тип переменной, чтобы решить, какой метод вызывать.
- среда выполнения просматривает фактический класс, на который указывает переменная, чтобы решить, откуда получить метод.
Итак, когда у вас есть:
Moe stooge2 = new Larry();
stooge2.print(new Moe());
компилятор говорит:
- можно ли назначить Ларри в stooge2?(да, поскольку Ларри является подклассом Moe)
- есть ли у Moe метод печати (Moe)?(да)
среда выполнения говорит:
- Предполагается, что я должен вызвать метод print (Moe) для этого объекта here ...марионетка 2
- stooge2 указывает на Ларри.
- Я вызову метод print(Moe) в классе Larry.
Как только вы со всем этим разберетесь, попробуйте избавиться от некоторых методов и посмотрите, как это все меняет.
Другие советы
На самом деле, эта проблема не так проста, как кажется, поскольку Java является одновременно статической и динамически привязанной.Вы должны понять, где применяется каждый из них, прежде чем поймете все результаты, которые вы получаете от этого упражнения.
Общее правило, упомянутое TofuBeer, верно только в случае динамической привязки.При статическом привязывании решения принимаются только во время компиляции.
В вашем примере смешивается динамическая привязка (когда методы переопределены) и статическая привязка (когда методы перегружены).
Взгляните на этот вопрос для получения более подробной информации.
Подсказка заключается в том, чтобы не обращать внимания на значение слева при просмотре объектов.Вместо этого посмотрите на значение права во время объявления, это фактическое значение объекта.