Абстрактні класи та інтерфейси



Дисципліна: «Професійна практика програмної інженерії» – 4 год лаб.роб № 2

зміст                                                                                                     { вісім завдань}

Наслідування, інтерфейси і пакети   165    01                      Назви проектів

1. Основи наслідування                           165    01                      SubClassDemo

2. Конструктор підкласу                                          169    03                      SubConstrDemo

3. Перевизначення методів                       172    06                      SubClassDemo

4. Закриті члени класу                              177    08                      PrivateDemo

5. Об'єктні змінні суперкласу                   180    10                      SubRefDemo

6.,7. Абстрактні класи і інтерфейси       182    11

а) Абстрактні класи                                                11                      AbstractDemo

б) Використання интерфейсу                               14                      UsingInterfaceDemo

8. Інтерфейсна змінна                                               17                      InterfaceRefDemo

Пакети і рівні доступу                               193    18

Резюме                                                           195    19

Наслідування є одним з фундаментальних механізмів ООП. Механізм полягає в тому, що на основі вже існуючих класів можна створювати нові класи, які отримують, або успадковують, властивості вихідних класів. Такий підхід має кілька переваг. Перерахуємо лише деякі з них.

В першу чергу забезпечується високий ступінь прямий і зворотної сумісності програмного коду. Тобто створення нових класів можливо без внесення змін у вже існуючі. Модифікація вже існуючих класів автоматично враховується в нових класах.

По-друге, реалізація програмного коду на принципах успадкування підвищує його гнучкість і знижує вірогідність здійснення помилок. Тепер подробиці

Основи успадкування(наследования)

При створенні нового класу за основу беремо вже існуючий клас. В принципі, є два шляхи:

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

Другий спосіб створення нового класу на основі вже існуючого полягає у використанні механізму наслідування. У цьому випадку при створенні нового класу за допомогою спеціальних синтаксичних конструкцій робиться вказівка на автоматичне включення вмісту вихідного(початкового) класу в новому класі. Хоча при цьому і старий, і новий класи існують окремо, але вони у відомому сенсі(смысле) взаємозалежні. Особливість цієї залежності така, що дозволяє вибудовувати цілу ієрархію класів, достаточно зручну у використанні. Саме на методах реалізації наследованія зупинимося.

В першу чергу визначимося з термінологією. Клас, на основі якого створюється новий клас, називається батьківським класом, або суперкласом. Новий клас, який створюється на основі суперкласу, називається підкласом.

Як створити на основі суперкласу підклас? Для цього в сигнатурі підкласу {Сигнатура (лат. Signature - позначати, вказувати) - набір характеристик, однозначно ідентифікує об'єкт.} після ключового слова class та імені підкласу вказується ключове слово extends(поширюється) та ім'я суперкласу. Таким чином, синтаксис оголошення підкласу має такий вигляд:

class імя_подкласа extends імя_суперкласа {

Код_подкласа;

}

Безпосередньо код підкласу описується як в звичайному класі. При цьому слід мати на увазі, що в підкласі автоматично відомі і доступні поля і методи суперкласу (всі, за винятком закритих).

Успадковуються ті члени суперкласу, які не є закритими. Ті члени класів, з якими ми мали справу до цього, були за замовчуванням відкритими. Це особливість мови Java. Тут за умовчанням члени класу є відкритими, на відміну, наприклад, від мови C++, в якому за замовчуванням члени класу є закритими. Як оголошуються закриті члени класу і в чому їх особливість, пояснюється дещо пізніше. Крім відкритих і закритих членів класу, є ще захищені. Вони також описуються в цій главі. До тих пір, поки мова не зайшла про закриті членах класу, будемо виходити з того, що всі члени суперкласу успадковуються в підкласі.

Фактично, з деякими обмеженнями, мова йде про те, що код суперкласа автоматично неявно копіруется в програмний код підкласу. І хоча поля і методи суперкласу в підкласі не описані, вони там є і до них можна звертатися і використовувати, як якщо б вони були явно описані в підкласі. Розглянемо приклад, представлений в лістингу 8.1.

// Лістинг 8.1. Наслідування(Спадкування) класів

package subclassdemo;

import javax.swing.*;

// Суперкласс:

class Superclass{

// Поля суперкласса:

int number;

String name;

// Метод суперкласса:

void setNumber(int n){

number=n;}

}

// Подкласс:

class Subclass extends Superclass{

// Поле подкласса:

char symbol;

// Метод подкласса:

void setAll(int n,String txt,char s){

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

setNumber(n);

// Обращение к полю, описанному в суперклассе:

name=txt;

// Присваивание значения полю подкласса:

symbol=s;}

// Метод подкласса:

void show(){

// Отображение значений полей подкласса:

JOptionPane.showMessageDialog (null, ("Числовое поле: " +number

+ "\nТекстовое поле: "+ name + "\nСимвольное поле: " + symbol));

System.out.println("Числовое поле: "+number+"\nТекстовое поле: "

+name +"\nСимвольное поле: " + symbol);

/* System.out.println("Числовое поле: "+number);

System.out.println("Текстовое поле: "+name);

System.out.println("Символьное поле: "+symbol);*/}

}

// Головной клас програми

public class Subclassdemo {

// Класс с главным методом программы:

public static void main(String[] args)/*сигнатура методу*/{

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

Subclass obj=new Subclass();

// Присваивание полям объекта значений:

obj.setAll(100,"ТЕКСТ",'А');

// Отображение значений полей:

obj.show();

// Изменение значений полей объекта:

obj.setNumber(20);

obj.name="НОВЫЙ";

// Отображение значений полей:

obj.show(); }

}

Спочатку в програмі описаний клас Superclass, на основі якого потім буде створено новий клас Subclass. To є клас Superclass є суперкласом для класу Subclass (який, в свою чергу, є підкласом для класу Superclass).

Поняття суперкласу є відносним, оскільки клас може бути суперкласом по відношенню до одного класу і не бути суперкласом по відношенню до якогось іншого класу.

Підклас створюється на основі одного і тільки одного класу, оскільки в Java заборонено багаторазове успадкування, тобто створення нового класу одночасно з використанням декількох вже існуючих. Разом з тим, багаторівневе успадкування дозволено. У цьому випадку підклас суперкласу сам може бути суперкласом для іншого підкласу. Тобто допускається така схема створення класів: на основі класу А шляхом успадкування створюється клас В, на основі класу В створюється клас С і так далі.

У суперкласі Superclass описано два поля: целочисленное поле number і текстове поле name. Також в суперкласі описаний метод setNumber(), за допомогою якого можна задати значення поля number (значення, що привласнюється полю number, передається аргументом методу setNumber ()).

Клас Subclass створюється на основі класу Superclass шляхом успадкування, про що свідчить інструкція extends Superclass в сигнатурі (заголовку) класу Subclass. безпосередньо в тілі класу Subclass описано символьне поле symbol. Слід також пам'ятати, що в класі Subclass з класу Superclass успадковуються поля number, name і метод setNumber (). Тому, наприклад, у методі set All(), описаному в класі Subclass, цілком законним є звернення до цих полів і методам. Іншими словами, ситуація абсолютно така ж, як якби поля number і name, а також метод setNumber() були описані безпосередньо в класі Subclass.Наприклад, командою setNumber(n) в тілі методу setAll() присвоюється значення полю number. Значення полю name присвоюється командою name = txt, а значення полю symbol, описаного безпосередньо в підкласі, присвоюється командою symbol = s. Тут n, txt і s позначають аргументи методу setAll(). Звернення до успадкованим полях number і name і "рідного" полю symbol є і в методі show() класу Subclass. Методом в консольне вікно виводяться значення полів об'єкта підкласу.

До успадкованих полів і методів підкласу можна звертатися як до звичайних полів і методів і ззовні коду підкласу.

Приклад такого звернення можна знайти в головному методі програми main(). Зокрема, після створення командою Subclass obj=new Subclass() об'єкта підкласу командою obj.setAll(100, "ТЕКСТ",’А1’) полях об'єкта присвоюються значення, а командою obj.show() виконується висновок значень полів на консоль. Потім командами obj.setNumber(20) і obj.nаme = "НОВИЙ" значення успадкованих полів підкласу змінюються, і командою obj.show() ще раз виконується висновок значень полів об'єкта підкласу в консольне вікно. Результат виконання програми виглядає так:

Числове поле: 100

 Текстове поле: ТЕКСТ

Символьне поле: А

Числове поле: 2 0

Текстове поле: НОВИЙ

Символьне поле: А

Розглянутий приклад ілюструє лише базові принципи успадкування класів. Можливі й більш заплутані і хитромудрі ситуації. Розглянемо питання про створення конструктора підкласу.

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

Якщо з конструктором суперкласу все більш-менш ясно, оскільки суперклас є фактично звичайним класом, то зі створенням конструктора підкласу справи йдуть трохи складніше. Щоб окреслити проблему, звернемо увагу ось на що. Справа в тому, що при створенні об'єкта підкласу автоматично спочатку викликається конструктор суперкласу, і вже після цього безпосередньо конструктор підкласу. Якщо конструктору суперкласу аргументи передавати не потрібно, то все виглядає не так вже й погано. Але от якщо конструктор суперкласу повинен отримувати аргумент або аргументи і без цього не обійтися ніяк, то тут є про що задуматися.

Вихід із ситуації такий. При створенні конструктора підкласу необхідно передбачити спосіб виклику конструктора суперкласу. Для цього в код конструктора підкласу включається інструкція super з круглими дужками, в яких перераховуються аргументи, які передаються конструктору суперкласу. Інструкціяsuper повинна бути першою командою в коді конструктора підкласу. Приклад створення підкласу з описом конструктора підкласу приведений в лістингу 8.2.

//Лістингу 8.2. Конструктор підкласу

package subconstrdemo;

import javax.swing. *;

// Суперкласс:

class A{

// Поля суперкласса:

int number;

char symbol;

// Конструктор суперкласса без аргументов:

А() {

number=0;

symbol='A';

System.out.println("Конструктор без аргументов!");

show();}

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

A(int n) {

number=n;

symbol='B' ;

show();}

// Конструктор суперкласса с двумя аргументами:

A(int n,char s){

number=n;

symbol=s;

System.out.println("Конструктор с двумя аргументами!");

show();}

// Метод для отображения полей:

void show () {

System.out.println("Поля "+number+" и " + symbol + ".") ; }

}

// Подкласс:

class В extends A{

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

String text;

// Конструктор подкласса без аргументов:

В() {

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

super () ;

text="Без аргументов";

showText();}

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

В(String txt) {

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

super(txt.length());

text=txt;

showText();}

// Конструктор подкласса с тремя аргументами:

B(int n,char s,String txt){

// Вызов конструктора суперкласса (с двумя аргументами)

super(n,s);

text=txt;

showText();}

// Метод для отображения текстового поля:

void showText(){

System.out.println("Текстовое поле \""+text+"\".");}

}

// Головной клас програми

public class SubConstrDemo{

public static void main(String[] args){

// Создание объектов (анонимных) подкласса.

// Используются разные конструкторы:

new В();

new В("Один аргумент");

new В(100,'F',"Три аргумента");}

}

Суперклас називається А, а на його основі створюється підклас, який називається В. У суперкласу А два поля: целочисленное поле.namber і символьне поле symbol. Для суперкласу описані конструктори без аргументів, з одним аргументом і з двома аргументами. При виклику конструктора суперкласу, крім присвоювання значення полях, виводиться консольне повідомлення відповідного змісту. Для відображення значень полів використовуємо метод show (), який викликається безпосередньо з конструктора.

У підкласі описується ще одне текстове поле text, а також метод showText(), яким здійснюється виведення значення текстового поля на консоль. У класі описані три варіанти конструктора: без аргументів, з одним текстовим аргументом і з трьома аргументами. У кожному з цих конструкторів першою командою викликається конструктор базового класу. Так, в конструкторі підкласу без аргументів командою super() викликається конструктор суперкласу без аргументів. У конструкторі підкласу з одним аргументом (текстовий аргумент txt) викликається конструктор суперкласу з одним аргументом, для чого використовується команда super(txt.Length ()). Тут аргументом конструктору суперкласу передається кількість символів у текстовому аргументі конструктора підкласу. Для обчислення кількості символів в текстовій змінної викликається вбудований метод length ().

Нагадаємо, що текстова змінна, і змінна txt зокрема, - це об'єктна змінна класу String. У класі є метод length (), який у якості значення повертає кількість символів у тексті, який міститься в об'єкті, з якого викликається метод. Іншими словами, щоб дізнатися, скільки символів в тексті, "захованому" в txt, досить використовується інструкцією txt.length(). Детальніше методи роботи з текстом ще будуть обговорюватися. Тут це лише ілюстративний приклад.

У конструкторі підкласу з трьома аргументами першою командою super(n,s) викликається конструктор суперкласу з двома аргументами. Тут n і s - перший і другий аргументи конструктора підкласу відповідно.

У головному методі програми послідовно створюється три анонімних об'єкта підкласу. При цьому використовуються різні конструктори: без аргументов, з одним аргументом і з трьома аргументами. В результаті у вікні консолі з'являється наступна серія повідомлень:

Конструктор без аргументів!

Поля 0 і. А.

Текстове поле "Без аргументів".

Конструктор з одним аргументом!

Поля 13 і В.

Текстове поле "Один аргумент".

Конструктор з двома аргументами!

Поля 100 і F.

Текстове поле "Три аргументи".

Якщо в програмному коді конструктора підкласу явно не вказати команду виклику конструктора суперкласу, то це зовсім не означає, що конструктор суперкласу викликатися не буде. У цьому випадку автоматично викликається конструктор суперкласу без аргументів. Якщо такий конструктор у суперкласу відсутня, виникає помилка.

Перевизначення (переопределение) методів

Важливе місце успадкуванні займає перевизначення методів. Суть перевизначення методів пов'язана з тим, що програмний код успадкованого в підкласі методу може бути перевизначений. В результаті підклас має такий же метод (з такою ж назвою), що і суперклас, але виконуються вони по-різному.

Не плутайте перевизначення методу і перевантаження методу. При перевантаженні методу в класі створюється кілька варіантів одного методу: назва одне і те ж, але сигнатури повинні відрізнятися. При перевизначенні потрібно, щоб був суперклас і підклас. Перевизначення в підкласі має таку ж сигнатуру, що і метод в суперкласі.

Для перевизначення методу в підкласі необхідно заново описати успадкований метод в підкласі. Розглянемо приклад, представлений в лістингу 8.3.

// Лістинг 8.3. Перевизначення методу

package oderridedemo;

// Суперкласс A:

class A{

int first;

// Метод для присваивания значения

// полю без аргумента:

void set(){ // перевантажений метод set()

first=0;

System.out.println("Нулевое значение поля."); }

// Метод для присваивания значения

// полю с одним аргументом:

void set(int n) { // перевантажений метод set(int n)

first=n;

// Вызов метода для отображения поля:

show();}

// Метод для отображения поля:

void show() {

System.out.println("Поле "+first+"."); }

void showAll(){

System.out.println("Все поля - на экран!");

show();}

}

// Подкласс B:

class В extends A{

// Еще одно поле:

int second;

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

void set(int n) {

first=n;

second=n;

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

show();}

// Перегрузка метода:

void set(int m,int n){

second=n;

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

super.set(m);}

// Переопределение метода для отображения полей:

void show() {

System.out.println("Поля "+first+"и"+second+".");}

}

// Головной клас програми

public class Oderridedemo {

public static void main(String[] args)/*сигнатура метода*/ {

// Объект суперкласса:

A objA=new A() ;

// Методы суперкласса:

objA.set() ;

objA.set(100);

// Объект подкласса:

В objB=new В();

// Методы подкласса:

objB.set();

objB.second =-1;

objB.show();

objB.set(200);

objB.set(1,2);

// Метод showAll():

objA.showAll();

objB.showAll();}

}

У програмі є суперклас А і підклас В. У класу А всього одне целочисленное поле, яке називається first. Також у класу А є перевантажений метод set() для надання значення полю, метод show() для відображення значення поля і ще один метод showAll()пов'язаного з перевизначенням методів. Код цих методів має деякі особливості, тому обговоримо їх. По-перше, метод set() має два варіанти - без аргументів і з одним аргументом. Якщо метод викликається без аргументів, то полю first присвоюється нульове значення, а в консоль виводиться повідомлення "Нульове значення поля.". Якщо метод set() викликається з одним цілочисловим аргументом, то цей аргумент визначає значення поля first, а потім за допомогою методу show() відображається значення поля. У самому методі show() викликається команда виведення на консоль текстової фрази "Поле" і безпосередньо значення поля first.

Методом showAll() спочатку в консоль відображається текстове повідомлення "Все поля - на екран!", Після чого викликається метод show(). Тому, поки не вступило в силу успадкування, наявність методу showAll() особливого інтересу не викликає - метод робить практично те ж, що і метод show(). Але ситуація ще зміниться (про це ми будемо говорити при обговоренні результатів виконання програми).

У підкласі В додається ще одне числове поле, яке називається second. У класі автоматично успадковується(наследуется) поле first і варіант методу set() без аргументів. Варіант методу set() з одним аргументом перевизначається. У перевизначення методі set() з одним аргументом (назва аргументу n) командами first = n і second = n полях присвоюється однакові значення. Далі викликається метод show(). Важливо те, що метод show() перевизначається в підкласі В. Тому в даному випадку викликається той варіант методу show (), який описаний (перевизначений) в підкласі В. перевизначити метод show() так, що для об'єктів підкласу В методом відображаються значення обох полів (тобто first і second). Крім цього, в підкласі В перевантажується метод set() для випадку, коли йому передаються два аргументи - значення полів first і second. Особливість методу set() з двома аргументами пов'язана з тим, що спочатку присвоюється значення другому полю (полю second), а потім викликається метод set() з однім аргументом. Але тільки той варіант методу, який описаний в класі А.

Якщо ми просто напишемо інструкцію виду set(аргумент), то це буде виклик тієї версії методу set(), який перевизначений в підкласі B Щоб показати, що нам потрібен "старий" метод set(), описаний в суперкласі, перед ім'ям методу вказуємо інструкцію super. В результаті отримуємо інструкцію super.set (аргумент), якій викликається версія методу set() з одним аргументом, описана в класі А. На цьому особливість даного коду не обмежується, але зараз краще в подробиці не вдаватися.

Таким чином, ключове слово super може використовуватися не тільки для виклику конструктора суперкласу, але й для посилання на методи (і поля!) суперкласа (використовується у випадку перевизначення методів або перекриття успадкованих полів). Перекриття успадкованих полів - це ситуація, коли в підкласі описано поле з таким же ім'ям, що і успадковане поле з суперкласу. Цю ситуацію розглянемо пізніше.

У головному методі програми в класі OverrideDemo спочатку створюється об'єкт objА класу А, після чого перевіряється робота методу set() з різними аргументами. Потім створюється об'єкт objВ класу В і перевіряється робота методів set() і show(), але вже для класу В. Нарешті, командамі objA.showAll() і objВ.showAll() успадковані в класі В метод showAll() викликається послідовно з об'єкта класу А і об'єкта класу В. Результат виконання програми має наступний вигляд:

Нульове значення поля.

Поле 100.

Нульове значення поля.

Поля 0 і -1.

Поля 200 і 200.

Поля 1 і 2.

Всі поля - на екран!

Поле 100.

Всі поля - на екран!

Поля 1 і 2.

Обговоримо його докладніше. Перше повідомлення "Нульове значення поля." Відображається в результаті виконання команди objA.set(). В результаті виконання команди objA.set(lOO) отримуємо повідомлення "Поле 100.". Дане повідомлення - наслідок виклику методу show() в тілі методу set() (варіант з одним аргументом).

Коли виконується команда objB.set(), викликається той же метод set() без аргументів, який описаний в класі А і який успадковується без змін класом В. Тому знову бачимо повідомлення "Нульове значення поля.". Оскільки при цьому тільки поле first отримує значення (нульове), командою objB.second = -l присвоюємо значення й іншому полю. Потім слід команда objВ.show(). Тут викликається та версія методу show(), що описана в класі В. Тому на екрані з'являється повідомлення "Поля 0 і -1.". Коли виконується команда objВ.set(200), викликається перевизначення версія методу set() з одним аргументом.

В цьому методі полям присвоюються однакові значення, і викликається перевизначення версія методу show(). В результаті отримуємо повідомлення "Поля 200 і 200.". Далі, коли виконується команда objВ.set(1,2), викликається варіант методу set(), в якому полях присвоюються значення, причому нагадаємо схему виконання цього методу. Полю second присвоюється значення. Для присвоювання значення полю first викликається вихідний, чи не перевизначення варіант методу set() з одним аргументом. Поле first отримує своє значення. Але крім цього викликається ще й метод show() (див. Код методу set() з одним аргументом у класі А). Хоча все це описано в класі А, оскільки вихідний метод set() з двома аргументами, в тому місці, де потрібно викликати метод show(), викликається перевизначення версія методу show(). Тому в консольному вікні з'являється повідомлення "Поля 1 і 2.".

Іншими словами, при виклику методу set(), описаного в суперкласі, з підкласу, в тілі методу у відповідних місцях автоматично викликаються перевизначені версії інших методів. Ця властивість ілюструється на прикладі виклику методу showAll() з об'єктів різних класів. Нагадаємо, в методі виводиться повідомлення "Все поля - на екран!", Після чого викликається метод show() (який перевизначений в підкласі). Так от, якщо метод showAll() викликається з об'єкта суперкласу, використовується версія методу show() з суперкласу. Якщо метод showAll() викликається з об'єкта підкласу, використовується версія методу show() з підкласу.

Як зазначалося вище, назви полів підкласу можуть дублювати назви полів з суперкласу. Наприклад, якщо в суперкласі А описано поле int number, а в підкласі В, який створюється на основі класу А, також явно описано поле int number, то за замовчуванням, якщо в класі В виконати посилання number, отримаємо доступ до того полю, що описано в цьому підкласі. Щоб отримати доступ до поля, описаному в суперкласі, використовуємо посилання super.number.

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

Закриті члени класу

Вище ми вже робили натяки на те, що далеко не всі члени суперкласу успадкуються. Далі є рецепт, як цього домогтися. А саме, щоб член класу не успадковувався, його необхідно оголосити в суперкласі закритим. Для цього достатньо в описі поля або методу вказати ключове слово private.

Тут ще раз доречно(уместно) нагадати, що в Java члени класу за замовчуванням є відкритими. Тому щоб їх закрити, доводиться вживати деякі дії.

Таким чином, члени (поля і методи), оголошені в суперкласі з ключовим словом private, в підкласі не успадковуються. Сенс цього "не успадковуються" пояснимо на простому, але показовому прикладі. Звернемося до лістингу 8.4.

//Лістинг 8.4. Закриті члени класу

package privatedemo;

// Суперкласс с закрытыми членами:

class Base{

// Закрытое текстовое поле:

private String name;

// Закрытое числовое поле:

private int number;

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

Base(String name,int number){

this.name=name;

this.number=number;

}

// Закрытый метод суперкласса:

private void show(){

System.out.println("Объект с именем "+name);}

// Открытый метод суперкласса:

void showAll(){

// Обращение к закрытому методу суперкласса:

show();

// Обращение к закрытому полю суперкласса:

System.out.println("Числовое поле объекта равно "+number);}

// Открытый метод суперкласса:

void setAll(String name,int number){

// Обращение к закрытым полям суперкласса:

this.name=name;

this.number=number;} }

// Подкласс:

class SubBase extends Base{

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

SubBase(String str,int num){

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

super (str,num);

// Отображение закрытых "ненаследуемых" полей

// с помощью наследуемого открытого метода:

showAll();}

}

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

public class Privatedemo {

public static void main(String[] args){

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

SubBase obj=new SubBase("НОВЫЙ",1);

// Изменение значений "несуществующих" полей объекта

// подкласса:

obj.setAll("ТОТ ЖЕ САМЫЙ",2);

// Отображение значений "несуществующих" полей объекта //подкласса:

obj.showAll();}

}

У програмі оголошується суперклас з ім'ям Base і потім на його основі створюється підклас з ім'ям SubBase. У суперкласі Base оголошені два закритих поля (з ідентифікатором private): текстове name і целочісленное number. Конструктором цих полях присвоюються значення при створенні нового об'єкта суперкласу. Конструктору передається два аргументи. Крім того, в класі Base є також три методу (один закритий і два відкритих), які не повертають результат. Це метод set All (), який приймає два аргументи, які присвоюються в якості значеній закритим полях об'єкта. Закритим методом show () на консольне вікно виводиться повідомлення про значення текстового поля name. Аргументів у методу show () немає. Крім цих методів, в класі Base є ще один відкритий метод showAll (). Цим методом в консольне вікно виводяться два повідомлення зі значеннями закритих полів name і number. Причому для відображення значення текстового поля name в тілі відкритого методу showAll () викликається закритий метод show ().

З точки зору програмного коду в класі Base немає абсолютно ніякої різниці, маємо ми справу з закритим чи відкритим членом класу. Всі вони доступні всередині класу. Різниця між закритими і відкритими членами проявляється, тільки якщо ми намагаємося отримати доступ до членів класу ззовні, тобто з іншого класу.

На цьому код класу Base вичерпаний. На основі класу Base шляхом ууспадкування створюється його підклас SubBase. У цьому простому, але загадковому класі є тільки конструктор і успадковані з класу Base откритие методи set All () і showAll ().

У конструктора підкласу SubBase є два аргументи. Ці аргументи передаються конструктору суперкласу, який, нагадаємо викликається за допомогою інструкції super (). Після цього викликається метод showAll (). Власне, це все.

Якщо ми спробуємо всередині коду класу SubBase звернутися безпосередньо до полів number або name, або методом show (), отримаємо повідомлення про помилку, оскільки в класі SubBase вони не успадковуються. Разом з тим, метод showAll (), який успадковується і викликається в конструкторі класу SubBase, містить звернення до закритих неуспадковане членам суперкласса. Такий парадокс має просте пояснення і багато в чому пов'язаний з тим, що розуміти під терміном неуспадковується, а також з тим, як створюється об'єкт підкласу. Для створення останнього спочатку викликається конструктор суперкласу, який виділяє місце, в тому числі і під закриті члени суперкласу. Тому технічно закриті члени суперкласу в об'єкті підкласу присутні. Однак об'єкт не має до них прямого доступу. Однак доступ до цих членам мають відкриті методи, успадковані з підкласу. Відповідно, підклас "нічого не знає" про "неуспадковане" членах суперкласса. Саме в такому сенсі розумно інтерпретувати термін "не успадковуються" * про ці членах в підкласі нічого не відомо.

У головному методі програми командою SubBase obj = new SubBase ("НОВИЙ", 1) створюється об'єкт підкласу. Аргументи, передані конструктору підкласу, призначені для "неуспадковане" з суперкласу полів. Далі за допомогою команди obj.setAll ("ТОЙ ЖЕ САМИЙ", 2) виконується зміна значень "неіснуючих" полів. Тут визивается успадкований з суперкласу метод set All (). Нарешті, отображеніе значень "неіснуючих" полів виконується командою obj.showAll (). В результаті виконання програми отримуємо наступні повідомлення у вікні консолі:

Об'єкт з ім'ям НОВИЙ

Числове поле об'єкта равноi1

Об'єкт з ім'ям ТОЙ ЖЕ САМИЙ

Числове поле об'єкта дорівнює 2

Перші два повідомлення з'являються в результаті створення об'єкта подкласа. Це результат виклику методу showAll () в тілі конструктора. Два другіе повідомлення з'являються після виклику методу showAll () через об'єкт підкласу з головного в головному методі програми.

Немає сенсу звертатися до полів number і name або методу show () об'екта підкласу ob j в головному методі програми. Таких членів у об'єкту немає, і не потрібно будувати з цього приводу ілюзій. Більше того, якби ми створили у головному методі об'єкт суперкласу, то до його закритим полів і методів також не можна було б звернутися, хоча вони в об'єкта були б. Просто ці члени закриті. Вони доступні тільки всередині коду класу.

Об'єктні змінні суперкласу

У об'єктних змінних суперкласів є одне дуже корисне і важливе властивість. Ці змінні можуть посилатися на об'єкти підкласів. Правда, доступ через об'єктну змінну суперкласу можна отримати тільки до тих полів і методів підкласу, які описані в суперкласі, але від цього принадність ситуації не зменшується. Корисність зазначеної особливості об'єктних змінних суперкласів проілюструємо на прикладі, представленому в лістингу 8.5.

//Лістинг 8.5. Об'єктні змінні суперкласів

package subrefdemo;

// Суперкласс:

class Base{

// Текстовое поле суперкласса:

String name;

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

Base(String name){

this.name=name;}

// Метод для отображения значения поля:

void show () {

System.out.println ("Объект суперкласса: "+name) ; }

// Метод выводит приветствие:

void sayHello(){

System.out.println("Всем привет!");} }

// Подкласс:

class SubBase extends Base{

// Символьное поле подкласса:

char code;

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

SubBase(String name,char code){

super(name);

this.code=code;}

// Переопределение метода:

void show () {

System.out.println("Объект подкласса: "+name+". Код: "+code);}

}

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

public class Subrefdemo {

public static void main(String[] args){

// Объектная переменная суперкласса:

Base obj;

// Ссылка на объект суперкласса:

obj=new Base("Базовый");

// Обращение к методам объекта суперкласса:

obj.sayHello();

obj.show();

// Ссылка на объект подкласса:

obj=new SubBase("Производный",'А');

// Обращение к методам объекта подкласса:

obj.sayHello();

obj.show();}

}

У суперкласу Base є текстове поле name і два методи. Методом show () в консолі відображається текстове повідомлення зі значенням текстового поля. Методом sayHello () відображається просте текстове повідомлення. Крім цього, у суперкласу Base є конструктор з одним текстовим аргументом. Це значення, яке присвоюється текстовому полю name.

На основі суперкласу Base створюється підклас SubBase. Підклас SubBase успадковує текстове поле name суперкласу, а також його методи sayHello() і show(). Однак останній в підкласі перевизначається. Версія методу show() з підкласу SubBase відображає, крім значення успадкованого текстового поля name, ще й значення символьного поля code, яке безпосередньо описано в підкласі SubBase. У конструктора підкласу SubBase два аргументи: перший текстовий аргумент передается конструктору суперкласу, а другий символьний аргумент прісваівается як значення символьному полю code.

У головному методі програми командою Base obj оголошується об'ектная змінна obj суперкласу Base. Наступною командою obj = new Base ("Базовий") в якості значення цієї змінної прісваєвається посилання на новостворений об'єкт суперкласу зі значенням "Базовий" текстового поля name об'єкта. Командами obj.sayHello() і obj.show() викликаються методи об'єкта суперкласу. У результаті спочатку в консольному вікні з'являється повідомлення "Всім привіт!", а потім повідомлення "Об'єкт суперкласу: Базовий".

Після цього виконується команда obj = new SubBase("Похідний",1А!). Цією командою створюється об'єкт підкласу, а посилання на нього записується в об'єктну змінну суперкласу. Потім ми знову виконуємо вже знайомі команди obj.sayHello() і obj.show(). Формально команди виглядають так само, як і в попередньому випадку, але тепер змінна obj посилається на об'єкт підкласу. Виконання команди obj.sayHello() до сюрпризів не приводить: з'являється повідомлення "Всім привіт!". У цьому випадку через об'єктну змінну obj викликається метод sayHello(), успадкований з суперкласу. Чудеса починаються при виконанні команди obj.show(). В результаті виконання команди в консоль виводиться повідомлення "Об'єкт підкласу: Похідний. Код: А". Це повідомлення виводиться методом show (), перевизначення в підкласі. Результат виконання програми має вигляд:

Всім привіт!

Об'єкт суперкласу: Базовий

Всім привіт!

Об'єкт підкласу: Похідний. Код: А

Точно так само через об'єктну змінну obj можна звернутися до поля name, але не можна звернутися до поля code. Причина в тому, що поле name описано в суперкласі і успадковано в підкласі, а поле code описано безпосередньо в підкласі, тому звернутися до неї через об'єктну змінну суперкласу не можна.

Таким чином, об'єктна змінна суперкласу дозволяє звертатися до полів і методів підкласу, які успадковані з суперкласу. У разі методів, якщо має місце їх перевизначення, то викликається версія методу з підкласу.

Абстрактні класи та інтерфейси

Абстрактні класи

Клас може містити абстрактні методи. Абстрактний метод, в отлічії від звичайного, має сигнатуру, але не містить блоку з програмним кодом. Абстрактний метод оголошується з ключовим словом abstract. Після сигнатури абстрактного методу ставиться крапка з комою. Клас, що містить хоча б один абстрактний метод, також називається абстрактним. Описується такий клас з використанням все того ж ключового слова abstract.

Для абстрактного класу не може бути створений екземпляр класу, тобто об'єкт. Причина очевидна і пов'язана з тим, що абстрактний клас містить абстрактні методи, які неможливо виконувати, адже вони не містять тіла методу з програмним кодом, а тільки сигнатуру.

Фактично абстрактний класи цінні своїми абстрактними методами. Хоча може здатися, що необхідність в існуванні абстрактних методів відсутня, це далеко не так. Абстрактні класи створюються для того, щоб на їх основі, шляхом успадкування, створювати другте класи.

У цьому відношенні абстрактний клас з його абстрактними методами задає шаблон своїх підкласів. Конкретна "начинка" такого шаблону визначається програмним кодом підкласу. Приклад оголошення і використання абстрактного класу приведений в лістингу 8.6.


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

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






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