![]() Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Интерфейсные ссылки ⇐ ПредыдущаяСтр 3 из 3
При создании объектов класса в качестве типа объектной переменной может указываться имя реализованного в классе интерфейса. Другими словами, если класс реализует интерфейс, то ссылку на объект этого класса можно присвоить интерфейсной переменной — переменной, в качестве типа которой указано имя соответствующего интерфейса. Ситуация очень напоминает ту, что рассматривалась в предыдущей главе при наследовании, когда объектная переменная суперкласса ссылалась на объект подкласса. Как и в случае с объектными ссылками суперкласса, через интерфейсную ссылку можно сослаться не на все члены объекта реализующего интерфейс класса. Доступны только те методы, которые объявлены в соответствующем интерфейсе. С учетом того, что класс может реализовать несколько интерфейсов, а один и тот же интерфейс может быть реализован в разных классах, ситуация представляется достаточно пикантной. В листинге 2 приведен пример программы, в которой используются интерфейсные ссылки. Листинг 2. Интерфейсные ссылки // Интерфейс: interface Base{ int F(int n); } // Класс A реализует интерфейс Base: class A implements Base{ // Двойной факториал числа: public int F(int n){ if(n==1||n==2) return n; else return n*F(n-2); } } // Класс B реализует интерфейс Base: class B implements Base{ // Факториал числа: public int F(int n){ if(n< 1) return 1; else return n*F(n-1); } } class ImplDemo{ public static void main(String args[]){ // Интерфейсные переменные и создание объектов: Base refA=new A(); Base refB=new B(); // Объектные переменные и создание объектов: A objA=new A(); B objB=new B(); // Проверка работы методов: System.out.println(" 1: " +refA.F(5)); System.out.println(" 2: " +refB.F(5)); System.out.println(" 3: " +objA.F(5)); System.out.println(" 4: " +objB.F(5)); // Изменение интерфейсных ссылок: refA=objB; refB=objA; // Проверка результата: System.out.println(" 5: " +refA.F(5)); System.out.println(" 6: " +refB.F(5)); } } В интерфейсе Base объявлен всего один метод с названием F(), целочисленным аргументом и целочисленным результатом. Классы A и B реализуют интерфейс Base, причем каждый по-своему. В классе A метод F() описан так, что им возвращается в качестве результата двойной факториал от целочисленного аргумента (напомним, что по определению двойной факториал числа n есть произведение натуральных чисел до этого числа включительно «через два», то есть n!! = n(n-2)(n-4)…). В классе B методом F() вычисляется факториал числааргумента метода (произведение натуральных чисел от 1 до числа n включительно, то есть n! =n*(n-1)*(n-2)*…*2*1). При описании метода F() в обоих классах использована рекурсия. В главном методе программы командами Base refA=new A() и Base refB=new B() создаются два объекта классов A и B, причем ссылки на эти объекты записываются в интерфейсные переменные refA и refB. В качестве типа этих переменных указано имя интерфейса Base, а сами объекты создаются вызовом конструкторов соответствующих классов. Затем создаются еще два объекта классов A и B, и ссылки на них записываются в объектные переменные objA и objB соответственно. Для этого используются команды A objA=new A() и B objB=new B(). После этого с помощью объектных и интерфейсных переменных несколько раз вызывается метод F() с аргументом 5. Отметим, что 5!! =15 и 5! =120. Поэтому если вызывается версия метода, описанная в классе A, результатом является число 15, а для версии метода, описанной в классе B, результат есть число 120. В частности, при вызове метода через переменные objA и refA вызывается версия метода, описанная в классе A, а при вызове метода через переменные objB и refB — версия, описанная в классе B. После этого командами refA=objB и refB=objA ссылки «меняются местами»: интерфейсная переменная refA ссылается на объект класса B, а интерфейсная переменная refB — на объект класса A. После этого инструкцией refA.F(5) вызывается версия метода F() из класса B, а инструкцией refB.F(5) — версия метода F(), описанная в классе A. В результате выполнения программы получаем следующее: 1: 15 2: 120 3: 15 4: 120 5: 120 6: 15 В листинге 3 приведен другой пример, в котором один класс реализует несколько интерфейсов. Листинг 3. Реализация нескольких интерфейсов // Первый интерфейс: interface One{ void setOne(int n); } // Второй интерфейс: interface Two{ void setTwo(int n); } // Суперкласс: class ClassA{ int number; void show(){ System.out.println(" Поле number: " +number); } } // Подкласс наследует суперкласс и реализует интерфейсы: class ClassB extends ClassA implements One, Two{ int value; // Метод первого интерфейса: public void setOne(int n){ number=n; } // Метод второго интерфейса: public void setTwo(int n){ value=n; } // Переопределение метода суперкласса: void show(){ super.show(); System.out.println(" Поле value: " +value); } } class MoreImplDemo{ public static void main(String[] args){ // Интерфейсные переменные: One ref1; Two ref2; // Создание объекта: ClassB obj=new ClassB(); // Интерфейсные ссылки: ref1=obj; ref2=obj; // Вызов методов: ref1.setOne(10); ref2.setTwo(-50); // Проверка результата: obj.show(); } } Результат выполнения этой программы имеет вид: Поле number: 10 Поле value: -50 Кратко поясним основные этапы реализации алгоритма. Итак, имеются два интерфейса One и Two, которые реализуются классом ClassB. Кроме того, класс ClassB наследует класс ClassA. В каждом из интерфейсов объявлено по одному методу: в интерфейсе One метод setOne(), а в интерфейсе Two метод setTwo(). Оба метода не возвращают результат и имеют один целочисленный аргумент. У суперкласса ClassA объявлено поле int number и определен метод show(), который выводит значение поля на экран. При наследовании в подклассе ClassB этот метод переопределяется так, что выводит значения двух полей: наследуемого из суперкласса поля number и поля int value, описанного непосредственно в подклассе. В классе ClassB методы setOne() и setTwo() реализованы так, что первый метод присваивает значение полю number, второй — полю value. В главном методе программы создаются две интерфейсные переменные: переменная ref1 типа One и переменная ref2 типа Two. Кроме того, создается объект obj класса ClassB. В качестве значений интерфейсным переменным присваиваются ссылки на объект obj. Это возможно, поскольку класс ClassB реализует интерфейсы One и Two. Однако в силу того же обстоятельства через переменную ref1 можно получить доступ только к методу setOne(), а через переменную ref2 — только к методу setTwo(). Командами ref1.setOne(10) и ref2.setTwo(-50) полям объекта obj присваиваются значения, а командой obj.show() значения полей выводятся на экран.
|