Спадкування, поліморфізм, інкапсуляція

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

Клас (java class) описує пристрій і поведінку об'єктів. Пристрій описується через набір характеристик (властивостей), а поведінка - через набір доступних для об'єктів операцій (методів). Класи можна створювати на основі вже наявних, додаючи або перевизначаючи властивості і методи.

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

Спадкування є невід'ємною частиною Java. При використанні успадкування приймається до уваги, що новий клас, який успадковує властивості базового (батьківського) класу має всі ті властивості, яким володіє батько. У коді використовується операнд extends. після якого вказується ім'я базового класу. Тим самим відкривається доступ до всіх полів і методів базового класу.

Використовуючи спадкування, можна створити загальний "java class", який визначає характеристики, загальні для набору пов'язаних елементів. Потім можна успадковуватися від нього і створити додаткові класи, для яких визначити додаткові унікальні для них характеристики.

Головний успадковані клас в Java називають суперкласом super. Успадковує клас називають подклассом. Таким чином підклас - це спеціалізована версія суперкласу, яка успадковує всі властивості суперкласу і додає свої власні унікальні елементи.

Розглянемо приклад опису java class'a студента Student, який має ім'я, прізвище, вік, і номер групи. Клас студента будемо створювати на основі super класу користувача User, у якого вже визначені ім'я, прізвище та вік:

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

Ключове слово extends показує, що ми успадковуємо від класу User.

Ключове слово super

У конструкторі класу Student ми викликаємо конструктор батьківського класу через оператор super. передаючи йому весь необхідної набір параметрів. В Java ключове слово super позначає суперклас, тобто клас, похідним від якого є поточний клас. Ключове слово super можна використовувати для виклику конструктора суперкласу і для звернення до члена суперкласу, прихованого членом підкласу.

Розглянемо як відбувається спадкування з точки зору створення об'єкта:

Спочатку відкривається конструктор класу Student, після цього викликається конструктор суперкласу User, а потім виконуються залишилися операції в конструкторі Student. Така послідовність дій є цілком логічною і дозволяє створювати більш складні об'єкти на основі більш простих.

У суперкласу можуть бути кілька перевантажених версій конструкторів, тому можна викликати метод super () з різними параметрами. Програма виконає той конструктор, який відповідає зазначеним аргументів.

Друга форма ключового слова super діє подібно ключовим словом this. тільки при цьому ми завжди посилаємося на суперклас підкласу, в якому вона використана. Загальна форма має наступний вигляд:

Тут член може бути методом або змінної примірника. Подібна форма підходить в тих випадках, коли імена членів підкласу приховують члени суперкласу з такими ж іменами.

В результаті в консолі ми повинні побачити:

Перевизначення методів, Override

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

Якщо потрібно отримати доступ до версії перевизначених методу, визначеного в суперкласі, то необхідно використовувати ключове слово super.

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

В Java SE5 з'явилася Анотація @Override ;. Якщо необхідно перевизначити метод, то використовуйте @Override, і компілятор видасть повідомлення про помилку, якщо замість перевизначення буде випадково виконана перевантаження.

У Java можна успадковуватися тільки від одного класу.

В інформатиці инкапсуляцией (лат. En capsula) називається упаковка даних і / або функцій в єдиний об'єкт.

Основою інкапсуляції в Java є клас. Інкапсуляція означає, що поля об'єкта недоступні його клієнтам безпосередньо - вони ховаються від прямого доступу ззовні. Інкапсуляція оберігає дані об'єкта від несанкціонованого доступу, дозволяючи об'єкту самому керувати доступом до своїх даних.

модифікатори доступу

При описі класу використовуються модифікатори доступу. Модифікатори доступу можна розглядати як з позиції інкапсуляції так і успадкування. Якщо розглядати з позиції інкапсуляції, то модифікатори доступу дозволяють обмежити небажаний доступ до членів класу ззовні.

Для всіх класів даного пакету

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

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

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

Приклад простого опису робота

У представленому прикладі робота використовуються набори методів, початківці з set і get. Цю пару методів часто називають сетер / геттер. Дані методи використовуються для доступу до полів об'єкта. Найменування методу закінчуються найменуванням поля, що починається з великої літери.

У методах set ми передаємо значення через формальний параметр всередину процедури. У коді процедури ми присвоюємо значення змінної об'єкта / класу з використанням ключового слова this.

Використання ключового слова this необхідно, тому що найменування формального параметра збігається з найменуванням змінної об'єкта. Якби найменування відрізнялися б, то можна було б this НЕ іспользаванной.

Очевидно, доведеться написати деякий код, який для зображення малюнка буде послідовно перебирати всі примітиви, які необхідно вивести на екран, і викликати метод draw у кожного з них.

Людина, незнайомий з поліморфізмом, найімовірніше створить кілька масивів: окремий масив для кожного типу примітивів і напише код, який послідовно перебере елементи з кожного масиву і викличе у кожного елемента метод draw. В результаті вийде приблизно наступний код:

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

Після цього ми створюємо різні класи-спадкоємці: Square (Квадрат), Line (Лінія), Сircle (коло) і Triangle (Трикутник):

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

Спадкування, поліморфізм, інкапсуляція

Тепер перевіримо дивовижну можливість поліморфізму:

В консоль будуть виведені наступні рядки:

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

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

Перевантаження методу, overload

У процедурному програмуванні теж існує поняття поліморфізму, яке відрізняється від розглянутого механізму в ООП. Процедурний поліморфізм припускає можливість створення декількох процедур або функцій з однаковим ім'ям, але різними кількістю або типами переданих параметрів. Такі однойменні функції називаються перевантаженими, а саме явище - перевантаженням (overload). Перевантаження функцій існує і в ООП і називається перевантаженням методів. Прикладом використання перевантаження методів в мові Java може служити клас PrintWriter. який використовується зокрема для виведення повідомлень на консоль. Цей клас має безліч методів println, які розрізняються типами і / або кількістю вхідних параметрів. Ось лише кілька з них: