![]() Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Интерфейсы
Ранее неоднократно отмечалось, что в Java запрещено множественное наследование. Причина отказа от множественного наследования связана с теми потенциальными проблемами, которые могут при этом возникать. Однако множественное наследование открывает широкие перспективы для составления эффективных программных кодов и значительно повышает гибкость программ. Выход был найден в использовании интерфейсов. Интерфейсы во многом напоминают классы. Принципиально от класса интерфейс отличается тем, что содержит только сигнатуры методов без описания, а также поля-константы (поля, значения которых постоянны и не могут изменяться). Описание интерфейса аналогично к описанию класса, только ключевое слово class необходимо заменить ключевым словом interface. Как отмечалось, для методов интерфейса указываются только сигнатуры. Описываемые в интерфейсе поля по умолчанию считаются неизменяемыми (как если бы они были описаны с ключевым словом final) и статическими (то есть static). Таким образом, поля интерфейса играют роль глобальных констант. Практическое использование интерфейса подразумевает его реализацию. Эта процедура напоминает наследование абстрактных классов. Реализуется интерфейс в классе. Класс, который реализует интерфейс, должен содержать описание всех методов интерфейса. Методы интерфейса при реализации описываются как открытые. Один и тот же класс может реализовать одновременно несколько интерфейсов, равно как один и тот же интерфейс может реализовываться несколькими классами. Для реализации интерфейса в классе в сигнатуре заголовка класса указывается инструкция implements(). С учетом того, что реализующий интерфейс класс может одновременно наследовать еще и суперкласс, общий синтаксис объявления класса, который наследует суперкласс и реализует несколько интерфейсов, имеет следующий вид: class имя [extends суперкласс] implements интерфейс1, интерфейс2,...{ // тело класса } Если имеет место наследование классов, то после имени класса через ключевое слово extends указывается имя наследуемого суперкласса, затем идет ключевое слово implements. После ключевого слова implements через запятую перечисляются реализуемые в классе интерфейсы, а дальше все стандартно — указывается непосредственно тело класса. Напомним также, что перед ключевым словом class может размещаться ключевое слово public, определяющее уровень доступа класса. В листинге 1 приведен пример программы, в которой используется интерфейс. Листинг 1. Реализация интерфейса // Интерфейс: interface MyMath{ // Сигнатура метода: double Sinus(double x); // Константа: double PI=3.14159265358979; } // Класс реализует интерфейс: class MyClass implements MyMath{ // Реализация метода (вычисление синуса): public double Sinus(double x){ int i, n=1000; double z=0, q=x; for(i=1; i< =n; i++){ z+=q; q*=(-1)*x*x/(2*i)/(2*i+1); } return z; } } class MyMathDemo{ public static void main(String args[]){ MyClass obj=new MyClass(); // Использование константы: double z=MyClass.PI/6; // Вызов метода: System.out.println(" sin(" +z+")=" +obj.Sinus(z)); } } В программе использован интерфейс MyMath, а также классы MyClass и MyMathDemo. Класс MyClass реализует интерфейс MyMath. Класс MyMathDemo содержит главный метод программы. В интерфейсе MyMath объявлен метод (только сигнатура) с названием Sinus(). Метод имеет один аргумент типа double и возвращает результат того же типа. Кроме того, в интерфейсе объявлена константа PI типа double. Это приближенное значение числа π. Обращаем внимание, что хотя поле не содержит ни идентификатора final, ни идентификатора static в своем описании, оно является статической константой. Хотя это и не обязательно, названия полей интерфейсов принято записывать в верхнем регистре. Класс MyClass, как отмечалось, реализует интерфейс MyMath. Поскольку в интерфейсе объявлен всего один метод, его и следует описать в классе MyClass. В данном случае использован ряд Тейлора для синуса: sin(x) = x-x3/3! +x5/5! -x7/7! +… В главном методе программы создается объект obj класса MyClass и объявляется переменная z типа double. Этой переменной присваивается значение π /6. При этом используется константа PI, объявленная в интерфейсе MyMath. Константа статическая и наследуется в классе MyClass, поэтому ссылка на нее в главном методе программы выглядит как MyClass.PI. В самом же классе к этому полю можно обращаться просто по имени, то есть как PI. Далее для аргумента z вычисляется значение синуса и результат выводится на экран. В итоге получаем сообщение: sin(0.5235987755982984)=0.4999999999999995 Это достаточно близкий результат к точному значению 1/2. Для читателей, знакомых с языком программирования С++, концепция интерфейсов может показаться на первый взгляд несколько странной, а сам подход к использованию интерфейсов нерациональным. Но это далеко не так. Еще раз подчеркнем, что главное назначение интерфейсов в Java — реализация множественного наследования (точнее, это — альтернативная технология по отношению к множественному наследованию классов). Дело в том, что основная масса проблем, возникающих при множественном наследовании классов, связана со спецификой реализации наследуемых методов. Другими словами, проблемы обычно появляются при попытке реализации конкретного программного кода методов и не связаны с самой структурой наследования. Через реализацию интерфейсов проблема «конечного кода» сводится к минимуму, поскольку интерфейсы содержат только объявления методов, а конкретная реализация этих методов выполняется в классе на последнем уровне иерархической структуры классов и интерфейсов.
|