Лістинг 8.6. Абстрактний клас



package abstractdemo;

// Абстрактный класс:

abstract class Base{

// Текстовое поле:

String operation;

// Конструктор:

Base(String str) {

operation=str;}

// Абстрактный метод:

abstract int F(int n);

// Обычный метод (с вызовом абстрактного):

void show(int n){

System.out.printIn("Операция: "+operation);

System.out.printIn("Аргумент: "+n);

System.out.println("Значение: "+F(n));}}

// Подкласс абстрактного суперкласса:

class BaseA extends Base{

// Конструктор подкласса:

BaseA(){

// Вызов конструктора (абстрактного) суперкласса:

super("факториал");}

// Переопределение абстрактного метода:

int F(int n){

if(n==l) return 1;

else return n*F(n-l);}

}

// Еще один подкласс абстрактного суперкласса:

class BaseB extends Base{

// Вызов конструктора (абстрактного) суперкласса:

BaseB () {

// Вызов конструктора (абстрактного) суперкласса:

super("двойной факториал");}

// Переопределение абстрактного метода:

int F(int n){

if(n==l||n==2) return n;

else return n*F(n-2);}

}

//Головний клас

public class AbstractDemo {

public static void main(String[] args){

// Создание объекта первого подкласса:

BaseA A=new BaseA();

// Создание объекта второго подкласса:

BaseB B=new BaseB();

// Вызов метода из первого подкласса:

A.show(5);

// Вызов метода из второго подкласса:

В.show(5);}

}

Тут оголошується абстрактний класBase. Звертаємо увагу на наявність ключового слова abstract в описі класу. У класі є текстове поле operation і конструктор з одним текстовим аргументом (значення аргументу привласнюється як значення полю operation класу). Це банальна ситуація. Щодо нової є команда abstract int F(int n) (закінчується крапкою з комою!). Цією командою оголошується абстрактний метод. Щоб можна було проігнорувати тіло з програмним кодом методу (його просто немає!), Сигнатуру методу починаємо з ключового слова abstract. Метод називається F(), повертає значення типу int, і у нього один аргумент також типу int. При створенні підкласу на основі класу Base необхідно буде перевизначити цей метод (насправді термін визначити тут буде доречніше). Але на цьому програмний код класу Base не закінчується. У класу є звичайний, небстрактний, метод show(). Метод не повертає результат, і у нього один цілочисельний аргумент. Методом в консольне вікно виводиться три повідомлення. Перше складається з тексту "Операція:" і текстового значення поля operation. Друге повідомлення складається з тексту "Аргумент:" і значення аргументу, переданого методу show(). Третє повідомлення складається з тексту "Значення:" і значення, що повертається методом F(), якщо йому передати в якості аргументу те ж значення, що зазначено аргументом методу show().

Зверніть увагу: в тілі неабстрактне методу show() викликається абстрактний метод F(), який в класі Base оголошений, але не описаний.

На основі класу Base через успадкування створюється два різних підкласу. Вони називаються BaseA і BaseB. Розглянемо кожен з цих класів.

У класі BaseA конструктор не має аргументів. У ньому інструкцією super ("факторіал") викликається конструктор суперкласу з текстовим аргументом "факторіал". Це значення отримує поле operation. Також в класі перевизначається метод F(), для чого використана така інструкція:

int F (int n) {

if (n == l) return 1;

else return n * F (n-l);}

Це так звана рекурсія - в коді опису методу викликається цей же метод (але з іншим аргументом). В даному випадку метод F() запрограмований так, що він обчислює факторіал (добуток натуральних чисел, наприклад 5!=5 4 3 2 1) для значення аргументу. Методи обчислюється за наступною схемою: якщо аргумент дорівнює одиниці, методом повертається одиничне значення. В іншому випадку обчислюється вираз, що дорівнює добутку аргументу на результат обчислення методу з аргументом, зменшеним на одиницю. Для реалізації цієї схеми використаний умовний оператор.

Припустимо, необхідно обчислити вираз F(5). При його обчисленні завантажується код методу F() і спочатку перевіряється, чи рівний аргумент одиниці. В даному випадку це не так. Тому як результат повертається вираз 5*F(4). Щоб обчислити цей вираз, знову завантажується код методу і розраховується значення F(4). Для цього обчислюється вираз 4*F(3), і так далі, поки не буде обчислено вираз 2*F(1). Потім цей ланцюжок згортається в зворотному напрямку. Тому слід врахувати, що, хоча рекурсія дозволяє створювати ефектний програмний код, він не завжди ефективний з точки зору економії використання системних ресурсів.

У підкласі BaseB описаний конструктор без аргументу, в якому інструкцією super ("подвійний факторіал") викликається конструктор суперкласу. Також в класі перевизначається метод F(). Код методу такий:

int F (int n) {

if (n == 1 || n == 2) return n;

else return n*F(n-2);}

Тут також використана рекурсія. Методом обчислюється подвійний факторіал числа - добуток чисел через одне (наприклад, 5!! =5 3 1, а 6!!=6 4 2). Якщо значення аргументу методу дорівнює 1 або 2, то повертається відповідно 1 або 2. В іншому випадку повертається вираз, що дорівнює добутку значення аргументу на результат виклику методу F() з аргументом, зменшеним на два.

У методі main() в класі AbstractDemo командами BaseA A=newBaseA() і BaseB B=new BaseB() створюються об'єкти підкласів BaseA і BaseB відповідно. Потім командами A.show(5) і В.show(5) з кожного об'єкта викликається метод show (). У цьому методі, в свою чергу, викликається метод F(). Але в кожному підкласі цей метод перевизначений по-своєму. Результат виконання програми має такий вигляд:

Операція: факторіал

Аргумент: 5

Значення: 120

Операція: подвійний факторіал

Аргумент: 5

Значення: 15

Продовженням ідеї абстрактних класів є концепція інтерфейсів, широко використовувана в Java.

ІНТЕРФЕЙС

На відміну від абстрактного класу, який крім абстрактних методів, може ще містити звичайні методи і поля, в інтерфейсі всі методи абстрактні. Точніше, в інтерфейсі методи тільки описуються, але не визначаються (при цьому в описі методів ключове слово abstract вказувати не потрібно). Поля також можуть бути присутніми в інтерфейсі, але їм відразу потрібно присвоювати значення, і такі поля є за замовчуванням статичними і незмінними (тобто такими, як якщо б вони були описані з ідентифікаторами final і static). Ну і зрозуміло, ніяких конструкторів в інтерфейсі! Їм там просто нічого робити.

Зазвичай прийнято назви полів інтерфейсу вводити великими буквами. Такі поля грають роль констант.

Оголошується інтерфейс так само, як і клас (з урахуванням зазначених вище поправок на структуру інтерфейсу), тільки замість ключового слова class вказується ключове слово interface, тобто все це, загалом і в цілому, виглядає так:

interface ім’я_інтерфейса {

// Константи і оголошення методів

}

Нескладно здогадатися, що самі по собі інтерфейси, враховуючи неможливість створення на їх основі об'єктів, безпосередньо не використовуються. Але на основі інтерфейсів можна створювати класи. У цьому випадку говорять про реалізацію інтерфейсу. Реалізація інтерфейсу в класі припускає, що оголошені в інтерфейсі методи описані в цьому класі. При описі методу з інтерфейсу необхідно в сигнатурі методу вказати ключове слово public.

Ключове слово public означає, що відповідний член класу відкритий. Хоча в Java за замовчуванням і так всі члени класів відкриті, це різна ступінь "відкритості". Члени класу, зазначені без ключового слова public, доступні в межах пакету, а описані з ключовим словом public доступні і поза пакета. Що таке пакет, описується в цій главі дещо пізніше.

Якщо в класі описати не всі методи інтерфейсу, то цей клас буде абстрактним і його слід оголосити з ключовим словом abstract. Тобто ситуація фактично така, як якщо клас, при реалізації інтерфейсу, успадковує всі його члени (в першу чергу оголошені в інтерфейсі методи) оскільки за визначенням методи в інтерфейсі тільки описані, клас успадковує абстрактні методи. Якщо хоча б один з цих абстрактних методів у класі не описаний, клас буде містити абстрактний метод. А це означає, що клас абстрактний.

Для реалізації інтерфейсу в класі при описі класу в заголовку, після імені класу необхідно вказати ключове слово implements і ім'я інтерфейсу. У найбільш простому випадку синтаксис класу, що реалізовує інтерфейс, відповідає таким шаблоном:

class ім'я_класу implements імя_інтерфейса {

// код класу з реалізацією методів інтерфейсу

}

У лістингу 8.7. наведено приклад програми, в якій використовується інтерфейс.


Дата добавления: 2018-04-15; просмотров: 228; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!