2009-03-16 5 views
2

Я практикуюсь на экзамене и нашел образец проблемы, который полностью меня потерял. Для следующего кода, найти то, что выход:Динамическое связывание 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, я получил что-то совершенно другое:

 
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 

Первые несколько все в порядке, но тогда я действительно не понимаю. У кого-нибудь есть хорошее объяснение этой проблемы?

Благодаря

ответ

5

Я хотел бы начать с рисования картины ...

Moe - print(Moe) 
| 
Larry - print(Moe), print(Larry) 
| 
Curly - print(Moe), print(Larry), print(Curly) 

Тогда я бы следить за переменными:

  • Ларри - stooge1 -> Вьющиеся
  • Moe - stooge2 -> Ларри
  • Moe - stooge3 -> Вьющиеся
  • завитые - stooge4 -> Вьющиеся
  • Ларри - stooge5 -> Ларри

  • stooge1.print(new Moe())

    • stooge1 -> Вьющиеся так называет Curly.print (Moe)
  • ((Curly)stooge1).print(new Larry());

    • stooge1 -> Curly так называет Curly.print (новый Ларри())
  • ((Larry)stooge2).print(new Moe());

    • stooge2 -> Ларри так называет Larry.print (новый Moe());
  • stooge2.print(new Curly());
    Хорошо, это, где это становится немного сложнее (жаль, что я остановился один, прежде чем здесь)

    • stooge2 объявляется быть Моу. Поэтому, когда компилятор смотрит на то, что назвать, он будет вызывать метод печати (Moe). Затем во время выполнения он знает, что stooge2 является Ларри, поэтому он называет метод Larry.print (Moe).

и т.д ...

Позвольте мне знать, если после этого весь путь до конца не работает для вас.

(обновлено уточнить следующий)

Так общее правило:

  • компилятор смотрит на тип переменной, чтобы решить, какой метод для вызова.
  • runtime смотрит на фактический класс, на который указывает переменная, чтобы решить, откуда взять метод.

Так что, когда у вас есть:

Moe stooge2 = new Larry(); 
stooge2.print(new Moe()); 

компилятор говорит:

  • может Ларри быть назначен stooge2? (да, поскольку Ларри является подклассом Мо)
  • У Мо есть метод печати (Мо)? (Да)

исполняющая говорит:

  • Я должен вызвать метод печати (Мо) на этом здесь объект ... stooge2
  • stooge2 является точка на Ларри.
  • Я буду называть метод печати (Moe) в классе Ларри.

После того, как вы все проработали, попробуйте избавиться от некоторых методов и посмотреть, как это изменит ситуацию.

+0

первые 3 - прямые. Если вы можете продолжить следующие 3, которые помогут. Благодаря! –

+0

вышеуказанные изменения должны помочь. – TofuBeer

+0

@TofuBeer - Не совсем правильно. В чистой динамической привязке stooge2.print (new Curly()) напечатал бы «Larry 2» не «Larry 1», так как Curly расширяет Ларри. (На самом деле stooge2.print (новый Ларри()) был бы лучшим примером, так как он также напечатал бы «Larry 1» вместо «Larry 2». – Robin

0

Намек это игнорировать значение слева, если смотреть на объекты. Вместо этого посмотрите на значение права во время объявления, это фактическое значение объекта.

2

На самом деле эта проблема не так проста, как кажется, поскольку Java является как статической, так и динамически связанной. Вы должны понимать, где каждый применяется, прежде чем вы поймете все результаты, которые вы получаете от этого упражнения.

Общее правило, упомянутое TofuBeer, является правильным только в случае динамического связывания. При статической привязке решения принимаются только во время компиляции.

Ваш пример смешивает динамическое связывание (когда методы переопределены) и статическое связывание (когда методы перегружены).

Взгляните на at this question для получения более подробной информации.