Глава 8. Интерфейсы

В этой главе мы рассмотрим следующие вопросы:

·  Понятие интерфейса в Java

·  Реализация интерфейсов

·  Особенности интерфейсов

В предыдущей главе мы завершили ознакомление с тремя основными принципами объектно-ориентированного программирования: инкапсуляцией, наследованием и полиморфизмом. Интерфейсы – это особенность Java-программирования, очень широко применяемая на практике.

Описание проблемы

В предыдущих главах мы создали два класса автомобилей: Moscvich и Porsche. Мы обнаружили много общих параметров и методов, использовали наследование и выделили общие функциональные признаки в базовый класс Car. Потом мы создали классы Porsche и Moscvich, наследующие от класса Car. В результате, классы Porsche и Moscvich содержат только атрибуты и методы, специфичные для них.

Теперь рассмотрим еще одну часть функциональности, которую хотелось бы добавить к классам – обслуживание. Обычно перед прохождением техосмотра или в других случаях автомобили отправляют на СТО ( станцию технического обслуживания ), где механики выполняют следующие действия: меняют масло, меняют колодки, проверяют двигатель и т. д. В Java это можно представить классом Mechanic, в котором реализовано обслуживание Porsche и Moscvich.

Естественно, обслуживание Porsche и Moscvich различается, так что особенности надо учитывать в классах Porsche и Moscvich. Можно было бы, используя полиморфизм, создать метод tuneUp в классе Car, а затем реализовать дополнительную функциональность в классах Porsche и Moscvich.

НЕ нашли? Не то? Что вы ищете?

Листинг 8.1 показывает изменение класса. Листинг 8.2 показывает изменеия класса Moscvich. Листинг 8.3 показывает, как изменится класс Porsche.

Листинг 8.1 Car. java

public abstract class Car

{

...

public abstract void tuneUp();

public abstract void changeOil();

}

В класс Car добавлены два абстрактных метода для обслуживания автомобиля: tuneUp() и changeOil(). Реализация методов выполнена в классах Porsche и Moscvich.

Листинг 8.2 Moscvich. java

public class Moscvich extends Car

{

...

public void tuneUp()

{

System. out. println( "Tuning up a Moscvich..." );

}

public void changeOil()

{

System. out. println( "Changing a Moscvich 's oil..." );

}

...

}

Класс Moscvich изменен добавлением в него двух новых методов, реализующих абстрактные методы класса Car. Эти методы выполняют действия, специфичные для Moscvich.

Листинг 8.3 Porsche. java

public class Porsche extends Car

{

...

public void tuneUp()

{

System. out. println( "Tuning up a porsche..." );

}

public void changeOil()

{

System. out. println( "Changing a porsche's oil..." );

}

...

}

В класс Porsche также добавлены два новых методов, реализующих абстрактные методы класса Car. Эти методы выполняют действия, специфичные для Porsche.

Наконец, листинг 8.4 прказывает реализацию класса Mechanic1.

Листинг 8.4 Mechanic1.java

public class Mechanic1

{

public void service( Car car )

{

car. changeOil();

car. tuneUp();

}

public static void main( String[] args )

{

Porsche porsche = new Porsche();

Moscvich moscvich = new Moscvich ();

Mechanic1 mechanic = new Mechanic1();

mechanic. service( porsche );

mechanic. service(moscvich );

}

}

Класс Mechanic1 определяет один метод:

public void service( Car car )

Метод service() имеет один параметр – ссылку на объект Car, для которого вызываются абстрактные методы changeOil() и tuneUp().

Это все замечательно работает. Все новые автомобили должны наследовать от Car, создать свои методы, которые являются абстрактными в классе Car, и механик сможет обслужить их!

Но что произойдет, если надо обслужить объект класса Мотоцикл или трактор? Создавать новый класс механика? Но если механик знает, как заменить масло в автомобиле, он сумеет заменить масло и в мотоцикле.

Если мыслить концептуально, то автомобиль или любое другое средство передвижения должны обслуживаться механиком, то есть свойство обслуживания – это не свойство автомобиля, а функция механика. Автомобиль обладает способностью быть обслуживаемым, но не обслуживает себя сам. А раз так, то должен быть внешний по тоношению к автомобилю механизм, который обеспечивает функциональность обслуживания для любого транспортного средства. Любое транспортное средство, вне зависимости от, того, к какой иерархии оно принадлежит, должно быть обслужено механиком. Механизм для решения такой задачи – интерфейсы.

Интерфейс определяет набор методов, которые должны реализовываться всеми классами, которые хотят иметь доступ к этой функциональности. Интерфейс выглядит как класс, но используется ключевое слово interface, а всеми методы интерфейса являются абстрактными. Никакого общего поведения в методе не описывается.

Листинг 8.5 показывает определение нового интерфейса Serviceable.

Листинг 8.5 Serviceable. java

public interface Serviceable

{

public void changeOil();

public void tuneUp();

}

Как и классы, интерфейсы определены в файлах с расширением. java. Ключевое слово interface используется вместо class, а методы не имеют реализации. Поскольку интерфейсы всегда абстрактны, и их методы абстрактны, ключевое слово abstract не указывается.

Класс Car, созданный в этой главе, изменим и абстрактные методы tuneUp() и changeOil() удалим.

Листинг 8.6 показывает измененные классы Porsche2 и Moscvich2.

Листинг 8.6 Porsche2.java

public class Porsche2 extends Car implements Serviceable

{

...

public void tuneUp()

{

System. out. println( "Tuning up a porsche..." );

}

public void changeOil()

{

System. out. println( "Changing a porsche's oil..." );

}

...

}

Класс Porsche2 реализует интнрфейс Serviceable, что указывается с помощью ключевого слова implements:

public class Porsche2 extends Car implements Serviceable

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

Реализация интерфейса похожа на подписание контракта, в котором указывается, что в классе будут определены все методы, указанные в интерфейсе. Если Вы реализуете интерфейс Serviceable, Вы должны определить методы и changeOil() и tuneUp().

Листинг 8.7 показывает, как это делается в новом классе Moscvich2.

Листинг 8.7 Moscvich2.java

public class Moscvich2 extends Car implements Serviceable

{

...

public void tuneUp()

{

System. out. println( "Tuning up a Moscvich..." );

}

public void changeOil()

{

System. out. println( "Changing a Moscvich's oil..." );

}

...

}

Класс Moscvich2, как и Porsche2, реализует интерфейс Serviceable и обеспечивает реализацию обоих методов интерфейса Serviceable: changeOil() и tuneUp().

Ну а теперь создадим класс для механика по обслуживанию автомобилей и других транспортных средств. Листинг 8.8 показывает код для класса Mechanic2.

Листинг 8.8 Mechanic2.java

public class Mechanic2

{

public void service( Serviceable s )

{

s. changeOil();

s. tuneUp();

}

public static void main( String[] args )

{

Porsche2 porsche = new Porsche2();

Moscvich2 moscvich = new Moscvich2();

Mechanic2 mechanic = new Mechanic1();

mechanic. service( porsche );

mechanic. service(moscvich );

}

}

Как и в классе Mechanic1, Mechanic2 определяет единственный метод service. Этот метод имеет параметр типа Serviceable:

public void service( Serviceable s )

Итак, мы создали объект класса, реализующего интерфейс Serviceable, и передали ссылку на него в метод service. Именно это делается в методе main класса Mechanic2. A объекты типа Porsche2 и Moscvich2 создаются и передаются в метод service класса Mechanic2.

Когда Вы определяете метод, объявленный в интерфейсе, Вы не можете в нем вызывать другие методы, которых нет в интерфейсе. Например, в методе service класса Mechanic2 Вы можете вызвать методы changeOil и tuneUp, но не можете вызвать метод engageTurbos класса Porsche2.

Множественное наследование

Во многих языках программирования разрешено множественное наследование. Есть связанная с ним опасность, называемая алмазное наследование ( см. рис. 8.1).

Рис 8.1. Диаграмма алмазного наследования

На рис. 8.1 мы создали новый автомобиль PorscheMoscvich. Вы видите, что PorscheMoscvich наследует и от Porsche, и от Moscvich, которые оба наследуют от Car. Множество вопросов возникают, когда будут вызываться методы для автомобиля типа PorscheMoscvich. Рассмотрим метод accelerate. Если в классе PorscheMoscvich метод accelerate не переопределен, то как он будет разгоняться: как Porsche или как Moscvich? Кроме того в памяти для автомобиля типа PorscheMoscvich будут находиться две копии объекта Car. Если мы начнем выполнять старт автомобиля, то какая копия «поедет»? А для какой копии поле running будет установлено в true?

Из-за сложности Java не использует множественное наследование совсем. Множественное наследование заменяется на использование различных интерфейсов, реализованных в классе.

Синтаксис интерфейса

Обычно интерфейс определяется следующим образом:

[public] interface iname [extends i2name]

·  Можно использовать ключевое слово для методов abstract, но оно предполагается по умолчанию

·  Можно использовать ключевое слово public для методов, но оно предполагается по умолчанию

·  Можно применять static и final для полей, но это действует по умолчанию

Все интерфейсы public и abstract.

Реализация интерфейса

Классы, реализующие интерфейс, используют ключевое слово implements:

[public] [qualifiers] class classname implements iname [,i2name]

·  Классы могут реализовывать любое количество интерфейсов

·  Классы могут быть и abstract, и final

·  Класс может наследовать от другого класса и одновременно реализовывать интерфейсы

Использование интерфейсов для реализации множественного наследования

Интерфейсы применяются по многим причинам, и множественное наследование – лишь одна из них. Классический пример для описания множественного наследования – это мистический Пегас. Пегас – это лошадь с крыльями. Если мы хотим создать класс Pegasus, то он должен наследовать от Horse (лошади) и от Bird (птицы).

В Java лучший способ создать класс Pegasus – это создать два интерфейса и инкапсулировать в них функциональность лошади и птицы: HorseLike и BirdLike. Затем определить класс Pegasus, в котором реализовать оба интерфейса. Листинги 8.9 and 8.10 показывают, как это сделать.

Листинг 8.9 HorseLike. java

public interface HorseLike

{

public void winee(); //ржание

public void gallop();// скакать

}

Листинг 8.10 BirdLike. java

public interface BirdLike

{

public void chirp(); //щебетать

public void fly(); // летать

}

Листинг 8.11 иллюстрирует класс Pegasus.

Листинг 8.11 Pegasus. java

public class Pegasus implements HorseLike, BirdLike

{

public void winee() {

System. out. println( "winee!" );

}

public void gallop() {

System. out. println( "I can run fast!" );

}

public void chirp() {

System. out. println( "Chirp, chirp!" );

}

public void fly() {

System. out. println( "Look at me, I'm a flying horse!" );

}

}

Наш Пегас умеет скакать, летать, щебетать и ржать.

Применение интерфейсов для расширения возможностей класса

Другое частое использование интерфейсов – расширение функциональных возможностей классов, как мы это делали с классом Car, чтобы сделать его наследников технически обслуживаемыми. Какие функции выделить в интерфейс, а какие реализовать в базовом классе – это Ваше дело, но обычно в базовом классе функциональность реализуется в минимальном объеме: сюда включаются только поля и методы, безусловно, общие для всех объектов данного типа. А вся дополнительная функциональность реализуется через интерфейсы.

Интерфейсы против абстрактных классов

Когда применять интерфейсы, а когда абстрактные классы? Вот некоторые рекомендации:

·  Используйте абстрактные классы и методы, когда функциональность тесно связана только с объектами данного типа

·  Используйте интерфейс, когда функциональность может применяться достаточно широко и к другим несвязанным объектам.

Заключение

В этой главе Вы познакомились с понятием интерфейса в Java. Интерфейсы определяются также, как и классы, но с ключевым словом interface. Еще одно отличие от класса заключается в том, что в интерфейсе все методы поумолчанию public и abstract. Вы можете также определить поля в интерфейсе, но они должны быть static и final.

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

В следующей главе Вы познакомитесь с обработкой исключений в Java.

Контрольные вопросы

1.   Может ли быть интерфейс private?

2.   Можно ли обеспечить реализацию методов интерфейса по умолчанию?

3.   Как реализовать интерфейс?

4.   Что такое множественное наследование?

5.   В чем опасность множественного наследования?

6.   Когда применять интерфейсы, а когда – абстрактные классы?

Упражнения

Расширьте созданные в предыдущей главе классы добавлением двух интерфейсов: Eating определяет один метод eat() ( едим ), и Playing определяет один метод play() ( играем ). Каждый вид животного реализует эти методы в свойственной им манере. Создайте класс ZooKeeper (Дрессировщик), который обеспечивает функциональность по кормлению всех животных и игре с ними.

Основные порталы (построено редакторами)

Домашний очаг

ДомДачаСадоводствоДетиАктивность ребенкаИгрыКрасотаЖенщины(Беременность)СемьяХобби
Здоровье: • АнатомияБолезниВредные привычкиДиагностикаНародная медицинаПервая помощьПитаниеФармацевтика
История: СССРИстория РоссииРоссийская Империя
Окружающий мир: Животный мирДомашние животныеНасекомыеРастенияПриродаКатаклизмыКосмосКлиматСтихийные бедствия

Справочная информация

ДокументыЗаконыИзвещенияУтверждения документовДоговораЗапросы предложенийТехнические заданияПланы развитияДокументоведениеАналитикаМероприятияКонкурсыИтогиАдминистрации городовПриказыКонтрактыВыполнение работПротоколы рассмотрения заявокАукционыПроектыПротоколыБюджетные организации
МуниципалитетыРайоныОбразованияПрограммы
Отчеты: • по упоминаниямДокументная базаЦенные бумаги
Положения: • Финансовые документы
Постановления: • Рубрикатор по темамФинансыгорода Российской Федерациирегионыпо точным датам
Регламенты
Термины: • Научная терминологияФинансоваяЭкономическая
Время: • Даты2015 год2016 год
Документы в финансовой сферев инвестиционнойФинансовые документы - программы

Техника

АвиацияАвтоВычислительная техникаОборудование(Электрооборудование)РадиоТехнологии(Аудио-видео)(Компьютеры)

Общество

БезопасностьГражданские права и свободыИскусство(Музыка)Культура(Этика)Мировые именаПолитика(Геополитика)(Идеологические конфликты)ВластьЗаговоры и переворотыГражданская позицияМиграцияРелигии и верования(Конфессии)ХристианствоМифологияРазвлеченияМасс МедиаСпорт (Боевые искусства)ТранспортТуризм
Войны и конфликты: АрмияВоенная техникаЗвания и награды

Образование и наука

Наука: Контрольные работыНаучно-технический прогрессПедагогикаРабочие программыФакультетыМетодические рекомендацииШколаПрофессиональное образованиеМотивация учащихся
Предметы: БиологияГеографияГеологияИсторияЛитератураЛитературные жанрыЛитературные героиМатематикаМедицинаМузыкаПравоЖилищное правоЗемельное правоУголовное правоКодексыПсихология (Логика) • Русский языкСоциологияФизикаФилологияФилософияХимияЮриспруденция

Мир

Регионы: АзияАмерикаАфрикаЕвропаПрибалтикаЕвропейская политикаОкеанияГорода мира
Россия: • МоскваКавказ
Регионы РоссииПрограммы регионовЭкономика

Бизнес и финансы

Бизнес: • БанкиБогатство и благосостояниеКоррупция(Преступность)МаркетингМенеджментИнвестицииЦенные бумаги: • УправлениеОткрытые акционерные обществаПроектыДокументыЦенные бумаги - контрольЦенные бумаги - оценкиОблигацииДолгиВалютаНедвижимость(Аренда)ПрофессииРаботаТорговляУслугиФинансыСтрахованиеБюджетФинансовые услугиКредитыКомпанииГосударственные предприятияЭкономикаМакроэкономикаМикроэкономикаНалогиАудит
Промышленность: • МеталлургияНефтьСельское хозяйствоЭнергетика
СтроительствоАрхитектураИнтерьерПолы и перекрытияПроцесс строительстваСтроительные материалыТеплоизоляцияЭкстерьерОрганизация и управление производством