Философия Java

Переопределение против перегрузки


Давайте теперь взглянем на первый пример этой главы, но под другим углом зрения. В следующей программе интерфейс метода play( ) изменен в процессе переопределения, что означает, что Вы не переопределили этот метод, а вместо этого перегрузили его. Компилятор позволяет вам перегрузить метод, поэтому и не было никаких жалоб с его стороны. Но поведение метода вероятно отличается от того, что бы Вы хотели. Пример:

//: c07:WindError.java

// Случайное изменение интерфейса.

class NoteX { public static final int

MIDDLE_C = 0, C_SHARP = 1, C_FLAT = 2; }

class InstrumentX { public void play(int NoteX) { System.out.println("InstrumentX.play()"); } }

class WindX extends InstrumentX { // Упс! Изменился интерфейс метода:

public void play(NoteX n) { System.out.println("WindX.play(NoteX n)"); } }

public class WindError { public static void tune(InstrumentX i) { // ...

i.play(NoteX.MIDDLE_C); } public static void main(String[] args) { WindX flute = new WindX(); tune(flute); // Не желаемое поведедение!

} } ///:~

Здесь есть еще одна запутывающая сторона применения полиморфизма. В InstrumentX метод play( ) принимает int, который имеет идентификатор NoteX. Так что, даже если NoteX это имя класса, то оно так же может быть использовано и в качестве переменной, без возражений со стороны компилятора. Но в WindX, play( ) берет ссылку NoteX,

которая имеет идентификатор n. (Хотя Вы никогда не сможете осуществить play(NoteX NoteX) без сообщения об ошибке.) Поэтому кажется, что программист собирался переопределить play( ), но немного опечатался. Компилятор же в свою очередь понял, что это перегрузка (overload), а не переопределение (override). Заметьте, что если Вы следуете соглашению об именах в Java, то тогда идентификатор был бы noteX (в нижнем регистре "n"), что отделило бы его от имени класса.

В tune, InstrumentX

i посылает сообщение методу play( ), с одним из членов NoteX (MIDDLE_C) в качестве аргумента. Поскольку NoteX содержит определение int, то это означает, что будет вызвана int

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

Вывод программы:

InstrumentX.play()

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



Содержание раздела