Философия Java3
Шрифт:
А вот как выглядит реализация примера оркестра с использованием абстрактных классов и методов:
//. interfaces/music4/Musiс4 java // Абстрактные классы и методы package interfaces.music4; import polymorphism.music.Note, import static net mindview util Print *.
abstract class Instrument {
private int i; // Память выделяется для каждого объекта public abstract void play(Note n); public String whatO { return "Instrument"; } public abstract void adjustO,
}
class Wind extends Instrument { public void play(Note n) {
print("Wind playО " + n),
}
public String whatO { return "Wind"; } public void adjustO {}
}
class Percussion extends Instrument { public void play(Note n) {
printC'Percussion playO " + n).
}
public String whatO { return "Percussion", } public void adjustO {}
}
class Stringed extends Instrument { public void play(Note n) {
print ("Stringed playO " + n),
}
public String whatO { return "Stringed". } public void adjustO {}
}
class Brass extends Wind {
public void play(Note n) {
printCBrass.playO " + n);
}
public void adjustO { printC'Brass adjustO"), }
}
class Woodwind extends Wind { public void play(Note n) {
print("Woodwind playО " + n);
}
public String whatO { return "Woodwind", }
}
public class Music4 {
//
static void tune(Instrument i) {
//
i.piay(Note MIDDLE_C),
}
static void tuneAll (Instrument!!] e) { for(Instrument i e) tune(i).
}
public static void main(String[] args) {
// Восходящее преобразование при добавлении в массив Instruments orchestra = { new WindO. new PercussionO. new StringedO. new BrassO. new WoodwindО
}.
tuneAl1(orchestra).
}
} /* Output Wind.pi ayО MIDDLE_C Percussion playO MIDDLE_C Stringed playO MIDDLE_C Brass playO MIDDLE_C Woodwind pi ayО MIDDLE_C */// ~
Как видите, объем изменений минимален.
Создавать абстрактные классы и методы полезно, так как они подчеркивают абстрактность класса, а также сообщают и пользователю класса, и компилятору, как следует с ним обходиться. Кроме того, абстрактные классы играют полезную роль при переработке программ, потому что они позволяют легко перемещать общие методы вверх по иерархии наследования.
Интерфейсы
Ключевое слово interface становится следующим шагом на пути к абстракции. Оно используется для создания полностью абстрактных классов, вообще не имеющих реализации. Создатель интерфейса определяет имена методов, списки аргументов и типы возвращаемых значений, но не тела методов.
Ключевое слово interface фактически означает: «Именно так должны выглядеть все классы, которые реализуют данный интерфейс». Таким образом, любой код, использующий конкретный интерфейс, знает только то, какие методы вызываются для этого интерфейса,
Однако интерфейс представляет собой нечто большее, чем абстрактный класс в своем крайнем проявлении, потому что он позволяет реализовать подобие «множественного наследования» С++: иначе говоря, создаваемый класс может быть преобразован к нескольким базовым типам.
Чтобы создать интерфейс, используйте ключевое слово interface вместо class. Как и в случае с классами, вы можете добавить перед словом interface спецификатор доступа public (но только если интерфейс определен в файле, имеющем то же имя) или оставить для него дружественный доступ, если он будет использоваться только в пределах своего пакета. Интерфейс также может содержать поля, но они автоматически являются статическими (static) и неизменными (final).
Для создания класса, реализующего определенный интерфейс (или группу интерфейсов), используется ключевое слово implements. Фактически оно означает: «Интерфейс лишь определяет форму, а сейчас будет показано, как это работает». В остальном происходящее выглядит как обычное наследование. Рассмотрим реализацию на примере иерархии классов Instrument:
Классы Woodwind и Brass свидетельствуют, что реализация интерфейса представляет собой обычный класс, от которого можно создавать производные классы.
При описании методов в интерфейсе вы можете явно объявить их открытыми (public), хотя они являются таковыми даже без спецификатора. Однако при реализации интерфейса его методы должны быть объявлены как public. В противном случае будет использоваться доступ в пределах пакета, а это приведет к уменьшению уровня доступа во время наследования, что запрещается компилятором Java.
Все сказанное можно увидеть в следующем примере с объектами Instrument. Заметьте, что каждый метод интерфейса ограничивается простым объявлением; ничего большего компилятор не" разрешит. Вдобавок ни один из методов интерфейса Instrument не объявлен со спецификатором public, но все методы автоматически являются открытыми:
// interfaces/music5/Music5.java
// Интерфейсы.
package interfaces.music5;
import polymorphism.music.Note;
import static net.mindview.util.Print.*;
interface Instrument {
// Константа времени компиляции:
int VALUE = 5; // является и static, и final
// Определения методов недопустимы:
void play(Note n); // Автоматически объявлен как public
void adjustO;
}
class Wind implements Instrument { public void play(Note n) {
print(this + ".playO " + n);
}
public String toStringO { return "Wind"; } public void adjustO { print(this + ".adjustO"); }
}
class Percussion implements Instrument { public void play(Note n) {