Динамическое связывание Java
Я готовлюсь к экзамену и обнаружил примерную проблему, которая полностью меня теряет. Для следующего кода найдите вывод:
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, я получил что-то совершенно другое:
Кудрявый 1 Вьющиеся 2 Ларри 1 Ларри 1 Кудрявый 1 Кудрявый 1 Кудрявый 1 Вьющиеся 2 Кудрявый 3 Кудрявый 3 Кудрявый 1 Вьющиеся 2 Ларри 2 Ларри 2 Ларри 1
Первые несколько в порядке, но потом я действительно не понимаю. У кого-нибудь есть хорошее объяснение этой проблемы?
Спасибо
3 ответа
Я бы начал с рисования картины...
Moe - print(Moe)
|
Larry - print(Moe), print(Larry)
|
Curly - print(Moe), print(Larry), print(Curly)
Тогда я бы отслеживал переменные:
- Ларри - stooge1 -> Кудрявый
- Мое - stooge2 -> Ларри
- Мо - stooge3 -> вьющиеся
- Кудрявый - stooge4 -> Кудрявый
Ларри - stooge5 -> Ларри
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.
Как только вы поработаете со всем этим, попробуйте избавиться от некоторых методов и посмотрите, как это меняет ситуацию.
На самом деле, эта проблема не так проста, как кажется, поскольку Java является как статической, так и динамически связанной. Вы должны понять, где каждый из них применяется, прежде чем вы поймете все результаты, которые вы получаете от этого упражнения.
Общее правило, упомянутое TofuBeer, верно только в случае динамического связывания. При статическом связывании решения принимаются только во время компиляции.
Ваш пример смешивает динамическое связывание (когда методы переопределены) и статическое связывание (когда методы перегружены).
Посмотрите на этот вопрос для более подробной информации.
Подсказка - игнорировать значение слева при взгляде на объекты. Вместо этого посмотрите на значение right во время объявления, это фактическое значение объекта.