Розширення класу

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

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

Якщо підклас не перевизначає (Override) поведінка суперкласу, то він успадковує всі властивості суперкласу, оскільки, як уже говорилося, розширений клас успадковує поля і методи суперкласу

Прикладом з плеєрами Walkman можна скористатися і тут В останніх моделях плеєрів встановлюються два розєми для навушників, щоб одну і ту ж касету могли слухати відразу двоє В обєктно-орієнтованому світі модель з двома розємами розширює базову модель Ця модель успадковує всі характеристики і поведінку базової моделі і додає до них свої власні

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

двома розємами і з можливістю ведення переговорів є підкласом моделі з двома розємами, успадковує всі її властивості і додає до них свої власні

У Sony є й інші моделі плеєрів Пізніші серії розширюють можливості базової моделі – вони створюють підкласи на її основі і успадковують від неї властивості і поведінку

Давайте подивимося, як відбувається спадкування в Java Розширимо наш клас Point, щоб він представляв піксель на екрані монітора У новому класі Pixel до координат x і y додається інформація про колір пікселя:

class Pixel extends Point { Color color

public void clear() { superclear() color = null

}

}

Клас Pixel розширює як дані, Так і поведінку свого суперкласу Point Для даних це означає, що в класі Pixel зявляється додаткове поле color Pixel також розширює поведінку Point, перевизначаючи метод clear класу Point Ця концепція наочно зображена на малюнку:

Обєкт Pixel може використовуватися в будь-якій програмі, яка розрахована на роботу з обєктами Point Якщо методом необхідно передати параметр типу Point, можна замість нього передати обєкт Pixel – все буде нормально Замість обєкта класу Point можна користуватися обєктом підкласу Pixel це явище відоме під назвою

“Поліморфізм – один і той же обєкт (Pixel) виступає в декількох (полі-) Формах (

морф) І може використовуватися і як Pixel, і як Point

Поведінка Pixel розширює поведінку Point Воно може абсолютно перетворитися (наприклад, робота з квітами в нашому прикладі) або буде являти собою деяке обмеження старого поведінки, що задовольняє всім вихідним вимогам Прикладом останнього може служити обєкт класу Pixel, що належить деякому обєкту Screen (екран), в якому значення координат x і y обмежуються розмірами екрану У вихідному класі Point значення координат могли бути довільними, тому обмежені значення координат все одно лежать у вихідному (необмеженій) діапазоні

Розширений клас часто перевизначає поведінку свого суперкласу (Тобто класу, на основі якого він був створений), по-новому реалізуючи один або кілька успадкованих методів У наведеному вище прикладі ми переопределили метод clear, щоб він поводився так, як того вимагає обєкт Pixel, – метод clear, успадкований від Point, знає лише про існування полів Point, але, зрозуміло, не здогадується про присутність поля color, оголошеного в підкласі Pixel

Вправа 112

Напишіть набір класів, що відображають структуру сімейства плеєрів Sony Walkman Скористайтеся методами, щоб приховати всі дані, оголосіть останні з ключовим словом private, а методи – public Які методи повинні належати базовому класу Walkman Які методи додадуться в розширених класах

1101 Клас Object

Класи, для яких не вказано розширюваний клас, є неявним розширенням класу Object Всі номери обєкти полиморфно відносяться до класу Object, який є базовим класом для всіх посилань, які можуть ставитися до обєктів будь-якого класу:

Object oref = new Pixel()

oref = “Some String”

У цьому прикладі обєкту oref цілком законно присвоюються посилання на обєкти Pixel і String, незважаючи на те що ці класи не мають між собою нічого спільного – за винятком неявного суперкласу Object

У класі Object також визначається кілька важливих методів, розглянутих у розділі 3

1102 Виклик методів суперкласу

Щоб очищення обєктів класу Pixel відбувалася правильно, ми заново реалізували метод clear Його робота починається з того, що за допомогою посилання super викликається метод clear суперкласу Посилання super під багатьох відношеннях нагадує вже згадувану раніше посилання this, за тим винятком, що super використовується для посилань на члени суперкласу, тоді як this посилається на члени поточного обєкта

Виклик superclear () звертається до суперкласу для виконання методу clear точно так само, як він звертався б до будь-якого обєкта суперкласу – у нашому випадку, класу Point Після виклику superclear () слід новий код, який повинен привласнювати color деякий розумне початкове значення Ми вибрали null – тобто відсутність посилання на який-небудь обєкт

Що б сталося, якби ми не викликали superclear () Метод clear класу Pixel присвоїв би полю кольору значення null, але змінні x і y, успадковані від класу Point,

залишилися б без змін Ймовірно, подібна часткове очищення обєкта Pixel, при якій упускаються успадковані від Point поля, зявилася б помилкою в програмі

При виклику методу supermethod () runtime-система переглядає ієрархію класів до першого суперкласу, що містить method () Наприклад, якби метод clear був відсутній в класі Point, то runtime-система спробувала б знайти такий метод в його суперкласі і (у разі успіху) викликала б його

У всіх інших посиланнях при виклику методу використовується тип обєкта, А не тип посилання

на обєкт Наведемо приклад:

Point point = new Pixel()

pointclear () / / Використовується метод clear () класу Pixel

У цьому прикладі буде викликаний метод clear класу Pixel, незважаючи на те що змінна,

містить обєкт класу Pixel, оголошена як посилання на Point

111 Інтерфейси

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

повинні однаково добре працювати зі звязковим списком, хеш-таблицею або будь-який інший

структурою даних

Java використовує так званий інтерфейс – Деяка подоба класу, де методи лише оголошуються, але не визначаються Розробник інтерфейсу вирішує, які методи повинні підтримуватися в класах, реалізують даний інтерфейс, і що ці методи повинні робити Наведемо приклад інтерфейсу Lookup:

interface Lookup {

/ ** Повернути значення, асоційоване з імям, або

null, якщо такого значення не виявиться * / Object find (String name)

}

В інтерфейсі Lookup оголошується всього один метод find, який отримує значення (імя) типу String і повертає значення, асоційоване з даним імям, або null, якщо такого значення не знайдеться Для оголошеного методу не надається ніякої конкретної реалізації – вона повністю покладається на клас, в якому реалізується даний інтерфейс У фрагменті програми, де використовуються посилання на обєкти Lookup (обєкти, що реалізують інтерфейс Lookup), можна викликати метод find і отримати очікуваний результат незалежно від конкретного типу обєкта:

void processValues(String[] names, Lookup table) {

for (int i = 0 i &lt nameslength i++) { Object value = tablefind(names[i]) if (value = null)

processValue(names[i], value)

}

}

Клас може реалізувати довільну кількість інтерфейсів У наступному прикладі наводиться реалізація інтерфейсу Lookup для простого масиву (ми не стали реалізовувати методи для додавання або видалення елементів):

class SimpleLookup implements Lookup {

private String[] Names

private Object[] Values

public Object find(String name) {

for (int i = 0 i &lt Nameslength i++) {

if (Names[i]equals(name))

return Values[i]

}

return null

}

//

}

Інтерфейси, подібно класам, можуть розширюватися за допомогою ключового слова extends Інтерфейс може розширити один або декілька інших інтерфейсів, додати до них нові константи і методи, які повинні бути реалізовані в класі, реализующем розширений інтерфейс

Супертіпа класу називаються розширюваний їм клас і інтерфейси, які він реалізує, включаючи всі супертіпи цих класів та інтерфейсів Отже, тип обєкта – це не тільки клас, але і всі його супертіпи разом з інтерфейсами Обєкт може полиморфно використовуватися в суперкласі і у всіх суперінтерфейсах, включаючи будь-який їх супертіп

Вправа 113

Напишіть розширений інтерфейс Lookup з додаванням методів add і remove

Реалізуйте його в новому класі

112 Винятки

Що робити, якщо в програмі сталася помилка У багатьох мовах про неї свідчать незвичайні значення кодів повернення – наприклад, -1 Програмісти нерідко не перевіряють свої програми на наявність виняткових станів, так як вони вважають, що помилок бути не повинно. З іншого боку, пошук небезпечних місць і відновлення нормальної роботи навіть в прямолінійно побудованої програмі може затемнити її логіку до такої міри, що все що відбувається в ній стане зовсім незрозумілим Така найпростіша задача, як зчитування файлу в память, вимагає близько семи рядків в програмі Обробка помилок і виведення повідомлень про них збільшує код до

40 рядків Суть програми втрачається у перевірках як голка в стозі сіна – це, звичайно ж, небажано

При обробці помилок в Java використовуються перевіряються виключення (checked exceptions) Виняток змушує програміста зробити якісь дії при виникненні помилки Виняткові ситуації в програмі виявляються при їх виникненні, а не пізніше, коли необроблена помилка призведе до безлічі проблем

Метод, в якому виявляється помилка, збуджує (throw) виняток Воно може бути перехоплено (catch) кодом, що знаходяться далі в стеку виклику – завдяки цьому перший фрагмент може обробити виняток і продовжити виконання програми Неперехваченние винятку передаються стандартному оброблювачу Java, який

може повідомити про виникнення виняткової ситуації і завершити роботу потоку в програмі

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

Основна парадигма роботи з винятками Java укладена в послідовності try-catch-finally Спочатку програма намагається (try) щось зробити якщо при цьому виникає виняток, вона його перехоплює (Catch) і нарешті (finally), програма робить деякі підсумкові дії в стандартному коді або в коді обробника виключення –

залежно від того, що сталося

Нижче наводиться метод averageOf, який повертає середнє арифметичне двох елементів масиву Якщо який-небудь з індексів виходить за межі масиву, програма запускає виняток, в якому повідомляє про помилку Насамперед варто визначити новий тип винятку Illegal AverageException для виведення повідомлення про помилку Потім необхідно вказати, що метод averageOf збуджує це виняток, за допомогою ключового слова throws:

class IllegalAverageException extends Exception {

}

class MyUtilities {

public double averageOf(double[] vals, int i, int j)

throws IllegalAverageException

{

try {

return (vals[i] + vals[j]) / 2

} catch (IndexOutOfBounds e) {

throw new IllegalAverageException()

}

}

}

Якщо при визначенні середнього арифметичного обидва індекси i і j опиняються в межах меж масиву, обчислення відбувається успішно і метод повертає отримане значення Однак, якщо хоча б один з індексів виходить за межі масиву, збуджується виключення IndexOutOfBounds і виконується відповідний оператор catch Він створює і збуджує нове виключення IllegalAverageException – по суті, загальне виключення порушення меж масиву перетворюється в конкретний виняток, більш точно описує справжню причину Методи, що знаходяться далі в стеку виконання, можуть перехопити нове виключення і належним чином прореагувати на нього

Якщо виконання методу може призвести до виникнення перевіряються винятків, останні повинні бути оголошені після ключового слова throws, як показано на прикладі методу averageOf Якщо не вважати винятків RuntimeException і Error, а також підкласів цих типів виключень, які можуть збуджуватися в будь-якому місці програми, метод збуджує лише оголошені в ньому винятку – як прямо, за допомогою оператора throw, так і побічно, викликом інших методів, збуджуючих винятку

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

перевірка запобігає помилки в тих випадках, коли метод повинен обробляти виключення від інших методів, проте не робить цього Крім того, метод, що викликає ваш метод, може бути впевнений, що це не призведе до виникнення несподіваних винятків Саме тому винятки, які мають бути оголошені після ключового слова throws, називаються перевіряються винятками Винятки, які є розширеннями RuntimeException і Error, не потребують оголошенні та перевірці вони називаються непроверяемимі винятками

Вправа 114

Відредагуйте виняток IllegalAverageException так, щоб у ньому містився масив і індекси і при перехопленні цього винятку можна було дізнатися подробиці помилки

113 Пакети

Конфлікти імен стають джерелом серйозних проблем при розробці повторно використовуваного коду Як би ретельно ви не підбирали імена для своїх класів і методів, хто-небудь може використовувати цей же імя для інших цілей При використанні простих назв проблема лише поглиблюється – такі імена з більшою ймовірністю будуть задіяні ким-небудь ще, хто також захоче користуватися простими словами Такі імена, як set, get, clear і т д, зустрічаються дуже часто, і конфлікти при їх використанні виявляються практично неминучими

У багатьох мовах програмування пропонується стандартне рішення – використання префікса пакета перед кожним імям класу, типу, глобальної функції і так далі Угоди про префіксах створюють контекст імен (naming context), Який запобігає конфлікти імен одного пакета з іменами іншого Зазвичай такі префікси мають довжину в кілька символів і є скороченням назви

пакета – наприклад, Xt для X Toolkit або WIN32 для 32-розрядного Windows API

Якщо програма складається всього з декількох пакетів, ймовірність конфліктів префіксів невелика Однак, оскільки префікси є скороченнями, при збільшенні числа пакетів ймовірність конфлікту імен підвищується

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

пакета

Наведемо приклад методу, в якому повні імена використовуються для виведення поточної дати і часу за допомогою допоміжного класу Java з імям Date (про який розказано в главі 12):

class Date1 {

public static void main(String[] args) { javautilDate now = new javautilDate() Systemoutprintln(now)

}

}

Тепер порівняйте цей приклад з іншим, в якому для оголошення типу Date використовується ключове слово import:

import javautilDate

class Date2 {

public static void main(String[] args) { Date now = new Date() Systemoutprintln(now)

}

}

Пакети Java не до кінця дозволяють проблему конфліктів імен Два різних проекту можуть присвоїти своїм пакетам однакові імена Ця проблема вирішується тільки за рахунок використання загальноприйнятих угод про імена За найбільш поширеній з таких угод як префікс імені пакета використовується перевернуте імя домену організації в Internet Наприклад, якщо фірма Acme Corporation містить в Internet домен з імям acmecom, то розроблені їй пакети матимуть імена типу COMacmepackage

Точки, що розділяють компоненти імені пакета, іноді можуть призвести до непорозумінь, оскільки ті ж самі точки використовуються при виклику методів і доступі до полів у посиланнях на обєкти Виникає питання – що ж саме імпортується Новачки часто намагаються імпортувати обєкт Systemout, щоб не вводити його імя перед кожним викликом println Такий варіант не проходить, оскільки System є класом, а out – його статичним полем, тип якого підтримується методом println

З іншого боку, javautil є пакетом, так що допускається імпортування javautilDate (або javautil *, Якщо ви хочете імпортувати весь вміст пакету) Якщо у вас виникають проблеми з імпортуванням чого-небудь, зупиніться і переконайтеся в тому, що ви імпортуєте тип

Класи Java завжди обєднуються в пакети Імя пакета задається на початку файлу:

package comsungames

class Card

{

}

// ..

// ..

Якщо імя пакета не було зазначено в оголошенні package, клас стає частиною безіменного пакету Хоча це цілком підходить для застосування (або аплета), яке використовується окремо від іншого коду, всі класи, які призначаються для використання в бібліотеках, повинні включатися в іменовані пакети

Джерело: Арнольд К, Гослінг Д – Мова програмування Java (1997)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*